fix some shell typos
authorHavoc Pennington <hp@redhat.com>
Mon, 7 May 2001 15:58:47 +0000 (15:58 +0000)
committerHavoc Pennington <hp@src.gnome.org>
Mon, 7 May 2001 15:58:47 +0000 (15:58 +0000)
2001-05-04  Havoc Pennington  <hp@redhat.com>

* configure.in: fix some shell typos

* gtk/gtkcolorsel.c (gtk_color_selection_destroy): warning fix

* gtk/gtkimage.c: handle animations

* gtk/gtkcheckbutton.c (gtk_check_button_size_request): request
border_width * 2, not just border_width

* gtk/gtkscale.c: add "format_value" signal to allow people
to override the way values are drawn.
(gtk_scale_get_value_size): fix width/height mistake,
and compute size from actual displayed text, not
from made-up text.

* gtk/gtktexttag.c (gtk_text_tag_class_init): fix return type in
signal registration

* tests/testtext.c: Add "Remove all tags" menu item for testing

* gtk/gtktextbuffer.c (gtk_text_buffer_remove_all_tags): implement

* demos/gtk-demo/main.c (main): add hack so we can find modules
without installing gtk

* demos/gtk-demo/textview.c (insert_text): demo font scaling

* gtk/gtkcellrenderertext.c: Add "scale" property (font scaling
factor)
(gtk_cell_renderer_text_set_property): remove some bogus
g_object_notify

* gtk/gtktexttag.c: add "scale" property which is a font scaling
factor

* gtk/gtktextlayout.c (add_text_attrs): add font scale attribute
to layout

* gtk/gtktextiter.c (gtk_text_iter_is_start): rename from
gtk_text_iter_is_first

2001-05-04  Havoc Pennington  <hp@redhat.com>

* pixops/pixops.c (pixops_process): merge fix from stable: Patch
 from hoshem@mel.comcen.com.au to fix nonzero X offsets.  Fixes
 bug #50371.

        * gdk-pixbuf/pixops/pixops.c (pixops_composite_nearest): merge
from stable: Patch from OKADA Mitsuru <m-okada@fjb.co.jp> to fix
confusion of using "src" instead of "p".
        (pixops_composite_color_nearest): Use a more accurate (and
correct, to begin with) compositing method.  This cures checks
showing through on images with no alpha.

* gdk-pixbuf.c (gdk_pixbuf_fill): fix bug that left some trailing
bytes unfilled.

* gdk-pixbuf-io.h: fix UpdatedNotifyFunc to use signed ints

* gdk-pixbuf-loader.h (struct _GdkPixbufLoaderClass): Change
area_updated signal to use signed ints.  Removed animation-related
signals.

* io-gif.c, io-gif-animation.h, io-gif-animation.c: Massive
rewrite action

* gdk-pixbuf-animation.c: Add GdkPixbufAnimationIter to abstract
all the pesky details. Remove old frame-based API. Make
GdkPixbufAnimation an abstract base class, derived by the loaders.

77 files changed:
ChangeLog
ChangeLog.pre-2-0
ChangeLog.pre-2-10
ChangeLog.pre-2-2
ChangeLog.pre-2-4
ChangeLog.pre-2-6
ChangeLog.pre-2-8
configure.in
demos/gtk-demo/Makefile.am
demos/gtk-demo/alphatest.png [new file with mode: 0644]
demos/gtk-demo/floppybuddy.gif [new file with mode: 0644]
demos/gtk-demo/images.c
demos/gtk-demo/main.c
demos/gtk-demo/textview.c
demos/testanimation.c
docs/reference/ChangeLog
docs/reference/gdk-pixbuf/tmpl/animation.sgml
docs/reference/gdk-pixbuf/tmpl/gdk-pixbuf-loader.sgml
docs/reference/gdk-pixbuf/tmpl/module_interface.sgml
docs/reference/gtk/gtk-sections.txt
docs/reference/gtk/tmpl/gtk-unused.sgml
docs/reference/gtk/tmpl/gtkimage.sgml
docs/reference/gtk/tmpl/gtkrc.sgml
docs/reference/gtk/tmpl/gtkscale.sgml
docs/reference/gtk/tmpl/gtksignal.sgml
docs/reference/gtk/tmpl/gtkstyle.sgml
docs/reference/gtk/tmpl/gtktextiter.sgml
docs/reference/gtk/tmpl/gtktexttag.sgml
docs/reference/gtk/tmpl/gtktypeutils.sgml
docs/reference/gtk/tmpl/gtkwindow.sgml
gdk-pixbuf/ChangeLog
gdk-pixbuf/Makefile.am
gdk-pixbuf/gdk-pixbuf-animation.c
gdk-pixbuf/gdk-pixbuf-io.h
gdk-pixbuf/gdk-pixbuf-loader.c
gdk-pixbuf/gdk-pixbuf-loader.h
gdk-pixbuf/gdk-pixbuf-private.h
gdk-pixbuf/gdk-pixbuf-util.c
gdk-pixbuf/gdk-pixbuf.c
gdk-pixbuf/gdk-pixbuf.h
gdk-pixbuf/io-bmp.c
gdk-pixbuf/io-gif-animation.c [new file with mode: 0644]
gdk-pixbuf/io-gif-animation.h [new file with mode: 0644]
gdk-pixbuf/io-gif.c
gdk-pixbuf/io-ico.c
gdk-pixbuf/io-jpeg.c
gdk-pixbuf/io-png.c
gdk-pixbuf/io-pnm.c
gdk-pixbuf/io-ras.c
gdk-pixbuf/io-tiff.c
gdk-pixbuf/io-wbmp.c
gdk-pixbuf/io-xbm.c
gdk-pixbuf/io-xpm.c
gdk-pixbuf/pixops/pixops.c
gtk/gtkcellrenderertext.c
gtk/gtkcellrenderertext.h
gtk/gtkcheckbutton.c
gtk/gtkcolorsel.c
gtk/gtkhscale.c
gtk/gtkimage.c
gtk/gtkimage.h
gtk/gtkmarshal.list
gtk/gtkmarshalers.list
gtk/gtkrange.h
gtk/gtkscale.c
gtk/gtkscale.h
gtk/gtktextbuffer.c
gtk/gtktextbuffer.h
gtk/gtktextiter.c
gtk/gtktextiter.h
gtk/gtktextlayout.c
gtk/gtktexttag.c
gtk/gtktexttag.h
gtk/gtktextview.c
gtk/gtkvscale.c
tests/testgtk.c
tests/testtext.c

index 2e672970f8318ee86d618f1f9f3a8d07bcefca13..924440869b531244bea9c7a8a01200e93432ef3f 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,46 @@
+2001-05-04  Havoc Pennington  <hp@redhat.com>
+
+       * configure.in: fix some shell typos
+
+       * gtk/gtkcolorsel.c (gtk_color_selection_destroy): warning fix
+
+       * gtk/gtkimage.c: handle animations
+
+       * gtk/gtkcheckbutton.c (gtk_check_button_size_request): request
+       border_width * 2, not just border_width
+
+       * gtk/gtkscale.c: add "format_value" signal to allow people
+       to override the way values are drawn.
+       (gtk_scale_get_value_size): fix width/height mistake,
+       and compute size from actual displayed text, not 
+       from made-up text.
+
+       * gtk/gtktexttag.c (gtk_text_tag_class_init): fix return type in 
+       signal registration
+
+       * tests/testtext.c: Add "Remove all tags" menu item for testing
+
+       * gtk/gtktextbuffer.c (gtk_text_buffer_remove_all_tags): implement
+
+       * demos/gtk-demo/main.c (main): add hack so we can find modules
+       without installing gtk
+
+       * demos/gtk-demo/textview.c (insert_text): demo font scaling
+
+       * gtk/gtkcellrenderertext.c: Add "scale" property (font scaling
+       factor)
+       (gtk_cell_renderer_text_set_property): remove some bogus
+       g_object_notify
+
+       * gtk/gtktexttag.c: add "scale" property which is a font scaling
+       factor
+
+       * gtk/gtktextlayout.c (add_text_attrs): add font scale attribute 
+       to layout
+
+       * gtk/gtktextiter.c (gtk_text_iter_is_start): rename from
+       gtk_text_iter_is_first
+
 2001-01-06  Hans Breuer  <hans@breuer.org>
 
        * gdk/gdk.def : updated exports
index 2e672970f8318ee86d618f1f9f3a8d07bcefca13..924440869b531244bea9c7a8a01200e93432ef3f 100644 (file)
@@ -1,3 +1,46 @@
+2001-05-04  Havoc Pennington  <hp@redhat.com>
+
+       * configure.in: fix some shell typos
+
+       * gtk/gtkcolorsel.c (gtk_color_selection_destroy): warning fix
+
+       * gtk/gtkimage.c: handle animations
+
+       * gtk/gtkcheckbutton.c (gtk_check_button_size_request): request
+       border_width * 2, not just border_width
+
+       * gtk/gtkscale.c: add "format_value" signal to allow people
+       to override the way values are drawn.
+       (gtk_scale_get_value_size): fix width/height mistake,
+       and compute size from actual displayed text, not 
+       from made-up text.
+
+       * gtk/gtktexttag.c (gtk_text_tag_class_init): fix return type in 
+       signal registration
+
+       * tests/testtext.c: Add "Remove all tags" menu item for testing
+
+       * gtk/gtktextbuffer.c (gtk_text_buffer_remove_all_tags): implement
+
+       * demos/gtk-demo/main.c (main): add hack so we can find modules
+       without installing gtk
+
+       * demos/gtk-demo/textview.c (insert_text): demo font scaling
+
+       * gtk/gtkcellrenderertext.c: Add "scale" property (font scaling
+       factor)
+       (gtk_cell_renderer_text_set_property): remove some bogus
+       g_object_notify
+
+       * gtk/gtktexttag.c: add "scale" property which is a font scaling
+       factor
+
+       * gtk/gtktextlayout.c (add_text_attrs): add font scale attribute 
+       to layout
+
+       * gtk/gtktextiter.c (gtk_text_iter_is_start): rename from
+       gtk_text_iter_is_first
+
 2001-01-06  Hans Breuer  <hans@breuer.org>
 
        * gdk/gdk.def : updated exports
index 2e672970f8318ee86d618f1f9f3a8d07bcefca13..924440869b531244bea9c7a8a01200e93432ef3f 100644 (file)
@@ -1,3 +1,46 @@
+2001-05-04  Havoc Pennington  <hp@redhat.com>
+
+       * configure.in: fix some shell typos
+
+       * gtk/gtkcolorsel.c (gtk_color_selection_destroy): warning fix
+
+       * gtk/gtkimage.c: handle animations
+
+       * gtk/gtkcheckbutton.c (gtk_check_button_size_request): request
+       border_width * 2, not just border_width
+
+       * gtk/gtkscale.c: add "format_value" signal to allow people
+       to override the way values are drawn.
+       (gtk_scale_get_value_size): fix width/height mistake,
+       and compute size from actual displayed text, not 
+       from made-up text.
+
+       * gtk/gtktexttag.c (gtk_text_tag_class_init): fix return type in 
+       signal registration
+
+       * tests/testtext.c: Add "Remove all tags" menu item for testing
+
+       * gtk/gtktextbuffer.c (gtk_text_buffer_remove_all_tags): implement
+
+       * demos/gtk-demo/main.c (main): add hack so we can find modules
+       without installing gtk
+
+       * demos/gtk-demo/textview.c (insert_text): demo font scaling
+
+       * gtk/gtkcellrenderertext.c: Add "scale" property (font scaling
+       factor)
+       (gtk_cell_renderer_text_set_property): remove some bogus
+       g_object_notify
+
+       * gtk/gtktexttag.c: add "scale" property which is a font scaling
+       factor
+
+       * gtk/gtktextlayout.c (add_text_attrs): add font scale attribute 
+       to layout
+
+       * gtk/gtktextiter.c (gtk_text_iter_is_start): rename from
+       gtk_text_iter_is_first
+
 2001-01-06  Hans Breuer  <hans@breuer.org>
 
        * gdk/gdk.def : updated exports
index 2e672970f8318ee86d618f1f9f3a8d07bcefca13..924440869b531244bea9c7a8a01200e93432ef3f 100644 (file)
@@ -1,3 +1,46 @@
+2001-05-04  Havoc Pennington  <hp@redhat.com>
+
+       * configure.in: fix some shell typos
+
+       * gtk/gtkcolorsel.c (gtk_color_selection_destroy): warning fix
+
+       * gtk/gtkimage.c: handle animations
+
+       * gtk/gtkcheckbutton.c (gtk_check_button_size_request): request
+       border_width * 2, not just border_width
+
+       * gtk/gtkscale.c: add "format_value" signal to allow people
+       to override the way values are drawn.
+       (gtk_scale_get_value_size): fix width/height mistake,
+       and compute size from actual displayed text, not 
+       from made-up text.
+
+       * gtk/gtktexttag.c (gtk_text_tag_class_init): fix return type in 
+       signal registration
+
+       * tests/testtext.c: Add "Remove all tags" menu item for testing
+
+       * gtk/gtktextbuffer.c (gtk_text_buffer_remove_all_tags): implement
+
+       * demos/gtk-demo/main.c (main): add hack so we can find modules
+       without installing gtk
+
+       * demos/gtk-demo/textview.c (insert_text): demo font scaling
+
+       * gtk/gtkcellrenderertext.c: Add "scale" property (font scaling
+       factor)
+       (gtk_cell_renderer_text_set_property): remove some bogus
+       g_object_notify
+
+       * gtk/gtktexttag.c: add "scale" property which is a font scaling
+       factor
+
+       * gtk/gtktextlayout.c (add_text_attrs): add font scale attribute 
+       to layout
+
+       * gtk/gtktextiter.c (gtk_text_iter_is_start): rename from
+       gtk_text_iter_is_first
+
 2001-01-06  Hans Breuer  <hans@breuer.org>
 
        * gdk/gdk.def : updated exports
index 2e672970f8318ee86d618f1f9f3a8d07bcefca13..924440869b531244bea9c7a8a01200e93432ef3f 100644 (file)
@@ -1,3 +1,46 @@
+2001-05-04  Havoc Pennington  <hp@redhat.com>
+
+       * configure.in: fix some shell typos
+
+       * gtk/gtkcolorsel.c (gtk_color_selection_destroy): warning fix
+
+       * gtk/gtkimage.c: handle animations
+
+       * gtk/gtkcheckbutton.c (gtk_check_button_size_request): request
+       border_width * 2, not just border_width
+
+       * gtk/gtkscale.c: add "format_value" signal to allow people
+       to override the way values are drawn.
+       (gtk_scale_get_value_size): fix width/height mistake,
+       and compute size from actual displayed text, not 
+       from made-up text.
+
+       * gtk/gtktexttag.c (gtk_text_tag_class_init): fix return type in 
+       signal registration
+
+       * tests/testtext.c: Add "Remove all tags" menu item for testing
+
+       * gtk/gtktextbuffer.c (gtk_text_buffer_remove_all_tags): implement
+
+       * demos/gtk-demo/main.c (main): add hack so we can find modules
+       without installing gtk
+
+       * demos/gtk-demo/textview.c (insert_text): demo font scaling
+
+       * gtk/gtkcellrenderertext.c: Add "scale" property (font scaling
+       factor)
+       (gtk_cell_renderer_text_set_property): remove some bogus
+       g_object_notify
+
+       * gtk/gtktexttag.c: add "scale" property which is a font scaling
+       factor
+
+       * gtk/gtktextlayout.c (add_text_attrs): add font scale attribute 
+       to layout
+
+       * gtk/gtktextiter.c (gtk_text_iter_is_start): rename from
+       gtk_text_iter_is_first
+
 2001-01-06  Hans Breuer  <hans@breuer.org>
 
        * gdk/gdk.def : updated exports
index 2e672970f8318ee86d618f1f9f3a8d07bcefca13..924440869b531244bea9c7a8a01200e93432ef3f 100644 (file)
@@ -1,3 +1,46 @@
+2001-05-04  Havoc Pennington  <hp@redhat.com>
+
+       * configure.in: fix some shell typos
+
+       * gtk/gtkcolorsel.c (gtk_color_selection_destroy): warning fix
+
+       * gtk/gtkimage.c: handle animations
+
+       * gtk/gtkcheckbutton.c (gtk_check_button_size_request): request
+       border_width * 2, not just border_width
+
+       * gtk/gtkscale.c: add "format_value" signal to allow people
+       to override the way values are drawn.
+       (gtk_scale_get_value_size): fix width/height mistake,
+       and compute size from actual displayed text, not 
+       from made-up text.
+
+       * gtk/gtktexttag.c (gtk_text_tag_class_init): fix return type in 
+       signal registration
+
+       * tests/testtext.c: Add "Remove all tags" menu item for testing
+
+       * gtk/gtktextbuffer.c (gtk_text_buffer_remove_all_tags): implement
+
+       * demos/gtk-demo/main.c (main): add hack so we can find modules
+       without installing gtk
+
+       * demos/gtk-demo/textview.c (insert_text): demo font scaling
+
+       * gtk/gtkcellrenderertext.c: Add "scale" property (font scaling
+       factor)
+       (gtk_cell_renderer_text_set_property): remove some bogus
+       g_object_notify
+
+       * gtk/gtktexttag.c: add "scale" property which is a font scaling
+       factor
+
+       * gtk/gtktextlayout.c (add_text_attrs): add font scale attribute 
+       to layout
+
+       * gtk/gtktextiter.c (gtk_text_iter_is_start): rename from
+       gtk_text_iter_is_first
+
 2001-01-06  Hans Breuer  <hans@breuer.org>
 
        * gdk/gdk.def : updated exports
index 2e672970f8318ee86d618f1f9f3a8d07bcefca13..924440869b531244bea9c7a8a01200e93432ef3f 100644 (file)
@@ -1,3 +1,46 @@
+2001-05-04  Havoc Pennington  <hp@redhat.com>
+
+       * configure.in: fix some shell typos
+
+       * gtk/gtkcolorsel.c (gtk_color_selection_destroy): warning fix
+
+       * gtk/gtkimage.c: handle animations
+
+       * gtk/gtkcheckbutton.c (gtk_check_button_size_request): request
+       border_width * 2, not just border_width
+
+       * gtk/gtkscale.c: add "format_value" signal to allow people
+       to override the way values are drawn.
+       (gtk_scale_get_value_size): fix width/height mistake,
+       and compute size from actual displayed text, not 
+       from made-up text.
+
+       * gtk/gtktexttag.c (gtk_text_tag_class_init): fix return type in 
+       signal registration
+
+       * tests/testtext.c: Add "Remove all tags" menu item for testing
+
+       * gtk/gtktextbuffer.c (gtk_text_buffer_remove_all_tags): implement
+
+       * demos/gtk-demo/main.c (main): add hack so we can find modules
+       without installing gtk
+
+       * demos/gtk-demo/textview.c (insert_text): demo font scaling
+
+       * gtk/gtkcellrenderertext.c: Add "scale" property (font scaling
+       factor)
+       (gtk_cell_renderer_text_set_property): remove some bogus
+       g_object_notify
+
+       * gtk/gtktexttag.c: add "scale" property which is a font scaling
+       factor
+
+       * gtk/gtktextlayout.c (add_text_attrs): add font scale attribute 
+       to layout
+
+       * gtk/gtktextiter.c (gtk_text_iter_is_start): rename from
+       gtk_text_iter_is_first
+
 2001-01-06  Hans Breuer  <hans@breuer.org>
 
        * gdk/gdk.def : updated exports
index 026edc15661b73029d95e5fee649b646bb946099..590460ff1f4a65d3201755589f1809aeb8f5b744 100644 (file)
@@ -563,18 +563,18 @@ AM_CONDITIONAL(HAVE_TIFF, test "x$LIBTIFF" != x)
 AM_CONDITIONAL(HAVE_PNG, test "x$LIBPNG" != x)
 AM_CONDITIONAL(HAVE_JPEG, test "x$LIBJPEG" != x)
 
-if test $dynworks = no ; then
+if $dynworks ; then
   STATIC_LIB_DEPS="$LIBTIFF $LIBJPEG $LIBPNG"
 else
   STATIC_LIB_DEPS=
   if echo "$included_loaders" | grep "\(^\|\,\)tiff\(\$\|\,\)" > /dev/null; then
-    STATIC_LIB_DEPS="STATIC_LIB_DEPS $LIBTIFF"
+    STATIC_LIB_DEPS="$STATIC_LIB_DEPS $LIBTIFF"
   fi
   if echo "$included_loaders" | grep "\(^\|\,\)jpeg\(\$\|\,\)" > /dev/null; then
-    STATIC_LIB_DEPS="STATIC_LIB_DEPS $LIBJPEG"
+    STATIC_LIB_DEPS="$STATIC_LIB_DEPS $LIBJPEG"
   fi
   if echo "$included_loaders" | grep "\(^\|\,\)png\(\$\|\,\)" > /dev/null; then
-    STATIC_LIB_DEPS="STATIC_LIB_DEPS $LIBPNG"
+    STATIC_LIB_DEPS="$STATIC_LIB_DEPS $LIBPNG"
   fi
 fi
 
index 3cb530503b59a152f7cca7c978491662786e6211..7d199e09c50957b972fca9579f2c3c010e3a1831 100644 (file)
@@ -59,8 +59,10 @@ gtk_demo_SOURCES =           \
 gtk_demo_DEPENDENCIES = $(DEPS)
 gtk_demo_LDADD = $(LDADDS)
 
-IMAGEFILES=    apple-red.png           \
+IMAGEFILES=    alphatest.png           \
+               apple-red.png           \
                background.jpg          \
+               floppybuddy.gif         \
                gnome-applets.png       \
                gnome-calendar.png      \
                gnome-foot.png          \
diff --git a/demos/gtk-demo/alphatest.png b/demos/gtk-demo/alphatest.png
new file mode 100644 (file)
index 0000000..eb5885f
Binary files /dev/null and b/demos/gtk-demo/alphatest.png differ
diff --git a/demos/gtk-demo/floppybuddy.gif b/demos/gtk-demo/floppybuddy.gif
new file mode 100644 (file)
index 0000000..ac986c8
Binary files /dev/null and b/demos/gtk-demo/floppybuddy.gif differ
index 353cb4c8c2f576535554ac24a1e21de86e79a785..7faeb53ccaeb18f39dcaa730166dec361743841c 100644 (file)
@@ -8,6 +8,8 @@
  *
  * If you want to put image data in your program as a C variable,
  * use the make-inline-pixbuf program that comes with GTK+.
+ * This way you won't need to depend on loading external files, your
+ * application binary can be self-contained.
  */
 
 #include <gtk/gtk.h>
@@ -39,14 +41,14 @@ progressive_prepared_callback (GdkPixbufLoader* loader, gpointer data)
 
 static void
 progressive_updated_callback (GdkPixbufLoader* loader,
-                              guint x, guint y, guint width, guint height,
+                              gint x, gint y, gint width, gint height,
                               gpointer data)
 {
   GtkWidget* image;
   
   image = GTK_WIDGET (data);
 
-  /* We know the pixbuf inside the image has changed, but the image
+  /* We know the pixbuf inside the GtkImage has changed, but the image
    * itself doesn't know this; so queue a redraw.  If we wanted to be
    * really efficient, we could use a drawing area or something
    * instead of a GtkImage, so we could control the exact position of
@@ -85,7 +87,7 @@ progressive_timeout (gpointer data)
                                            GTK_DIALOG_DESTROY_WITH_PARENT,
                                            GTK_MESSAGE_ERROR,
                                            GTK_BUTTONS_CLOSE,
-                                           "Failure reading image file 'gtk-logo-rgb.gif': %s",
+                                           "Failure reading image file 'alphatest.png': %s",
                                            g_strerror (errno));
 
           gtk_signal_connect (GTK_OBJECT (dialog),
@@ -180,10 +182,10 @@ progressive_timeout (gpointer data)
     {
       const gchar *filename;
 
-      if (g_file_test ("./gtk-logo-rgb.gif", G_FILE_TEST_EXISTS))
-        filename = "./gtk-logo-rgb.gif";
+      if (g_file_test ("./alphatest.png", G_FILE_TEST_EXISTS))
+        filename = "./alphatest.png";
       else
-        filename = DEMOCODEDIR"/gtk-logo-rgb.gif";
+        filename = DEMOCODEDIR"/alphatest.png";
       
       image_stream = fopen (filename, "r");
 
@@ -195,7 +197,7 @@ progressive_timeout (gpointer data)
                                            GTK_DIALOG_DESTROY_WITH_PARENT,
                                            GTK_MESSAGE_ERROR,
                                            GTK_BUTTONS_CLOSE,
-                                           "Unable to open image file 'gtk-logo-rgb.gif': %s",
+                                           "Unable to open image file 'alphatest.png': %s",
                                            g_strerror (errno));
 
           gtk_signal_connect (GTK_OBJECT (dialog),
@@ -246,7 +248,7 @@ start_progressive_loading (GtkWidget *image)
    * The timeout simply simulates a slow data source by inserting
    * pauses in the reading process.
    */
-  load_timeout = g_timeout_add (300,
+  load_timeout = g_timeout_add (150,
                                 progressive_timeout,
                                 image);
 }
@@ -359,6 +361,37 @@ do_images (void)
 
       gtk_container_add (GTK_CONTAINER (frame), image);
 
+
+      /* Animation */
+
+      label = gtk_label_new (NULL);
+      gtk_label_set_markup (GTK_LABEL (label),
+                            "<u>Animation loaded from a file</u>");
+      gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
+      
+      frame = gtk_frame_new (NULL);
+      gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
+      /* The alignment keeps the frame from growing when users resize
+       * the window
+       */
+      align = gtk_alignment_new (0.5, 0.5, 0, 0);
+      gtk_container_add (GTK_CONTAINER (align), frame);
+      gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 0);
+
+      /* We look for the image in the current directory first,
+       * so you can run gtk-demo without installing GTK
+       */
+      if (g_file_test ("./floppybuddy.gif", G_FILE_TEST_EXISTS))
+        image = gtk_image_new_from_file ("./floppybuddy.gif");
+      else
+        image = gtk_image_new_from_file (DEMOCODEDIR"/floppybuddy.gif");
+
+      gtk_container_add (GTK_CONTAINER (frame), image);
+      
+
+      /* Progressive */
+      
+      
       label = gtk_label_new (NULL);
       gtk_label_set_markup (GTK_LABEL (label),
                             "<u>Progressive image loading</u>");
index fabf898d44dc750e82b622be11a85c435bcf6d83..83a27b362f791506ed047306c6a03073ba6475ae 100644 (file)
@@ -465,6 +465,18 @@ main (int argc, char **argv)
   GtkWidget *tree;
   GtkTextTag *tag;
 
+  /* Most code in gtk-demo is intended to be exemplary, but not
+   * these few lines, which are just a hack so gtk-demo will work
+   * in the GTK tree without installing it.
+   */
+  if (g_file_test ("../../gdk-pixbuf/.libs/libpixbufloader-pnm.so",
+                   G_FILE_TEST_EXISTS))
+    {
+      putenv ("GDK_PIXBUF_MODULEDIR=../../gdk-pixbuf/.libs");
+      putenv ("GTK_IM_MODULE_FILE=../../modules/input/gtk.immodules");
+    }
+  /* -- End of hack -- */
+  
   gtk_init (&argc, &argv);
   
   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
index 928df9073b7e0f7b76d76ace6ae9b8a1f1385c1c..2fc970bfd480abcf9fdb77c13f5c088f63196f78 100644 (file)
@@ -84,6 +84,12 @@ create_tags (GtkTextBuffer *buffer)
                               /* points times the PANGO_SCALE factor */
                               "size", 30 * PANGO_SCALE, NULL);
 
+  gtk_text_buffer_create_tag (buffer, "xx-small",
+                              "scale", PANGO_SCALE_XX_SMALL, NULL);
+
+  gtk_text_buffer_create_tag (buffer, "x-large",
+                              "scale", PANGO_SCALE_X_LARGE, NULL);
+  
   gtk_text_buffer_create_tag (buffer, "monospace",
                               "family", "monospace", NULL);
   
@@ -199,8 +205,17 @@ insert_text (GtkTextBuffer *buffer)
   gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
                                             "big", -1,
                                             "big", NULL);
-  gtk_text_buffer_insert (buffer, &iter, " text.\n\n", -1);
-
+  gtk_text_buffer_insert (buffer, &iter, " text. ", -1);
+  gtk_text_buffer_insert (buffer, &iter, "It's best not to hardcode specific text sizes; you can use relative sizes as with CSS, such as ", -1);
+  gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
+                                            "xx-small", -1,
+                                            "xx-small", NULL);
+  gtk_text_buffer_insert (buffer, &iter, " or ", -1);
+  gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
+                                            "x-large", -1,
+                                            "x-large", NULL);
+  gtk_text_buffer_insert (buffer, &iter, " to ensure that your program properly adapts if the user changes the default font size.\n\n", -1);
+  
   gtk_text_buffer_insert_with_tags_by_name (buffer, &iter, "Colors. ", -1,
                                             "heading", NULL);
   
index a823249b42afc1480af9ad9382fa9403c42bafcc..82b932c2d0707868bf7759168ae897e5062558c4 100644 (file)
 #include <stdlib.h>
 #include <unistd.h>
 #include <string.h>
+#include <errno.h>
 #include <gtk/gtk.h>
-#include <gdk-pixbuf/gdk-pixbuf-loader.h>
-
-typedef struct {
-       FILE             *imagefile;
-       GdkPixbufLoader  *loader;
-       GtkWidget        **rgbwin;
-       guchar           *buf;
-       guint            timeout;
-       guint            readlen;
-
-} ProgressFileStatus;
-
-
-#define DEFAULT_WIDTH  24
-#define DEFAULT_HEIGHT 24
-
-static const unsigned char default_image[] = {
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0xae, 0xb3, 0xb3, 0xc6, 0xc9, 0xcd, 0xd7, 0xd4, 0xdf,
-       0xec, 0xde, 0xf3, 0xe7, 0xcb, 0xe9, 0xd9, 0xb5, 0xd3, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0xb1, 0xb7, 0xa5,
-       0xb0, 0xb8, 0xad, 0xb3, 0xb9, 0xb6, 0xc1, 0xc6, 0xc8, 0xd5, 0xd3, 0xdc,
-       0xec, 0xde, 0xf3, 0xe5, 0xca, 0xe6, 0xe0, 0xbb, 0xd7, 0xe1, 0xad, 0xc2,
-       0xe3, 0xac, 0xa3, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0xca, 0xc1, 0xa4, 0xc5, 0xc7, 0xac,
-       0xb7, 0xbe, 0xaf, 0xad, 0xb4, 0xaf, 0xbd, 0xc2, 0xc3, 0xd1, 0xd0, 0xd8,
-       0xec, 0xde, 0xf3, 0xe5, 0xc7, 0xe4, 0xe0, 0xb6, 0xd1, 0xe7, 0xa9, 0xb4,
-       0xed, 0xcd, 0xb6, 0xd6, 0xcf, 0xae, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0x00, 0x00, 0x00, 0xdf, 0xa7, 0x9f, 0xdd, 0xbf, 0xaa, 0xcf, 0xc5, 0xa9,
-       0xc1, 0xc4, 0xac, 0xb2, 0xba, 0xaf, 0xb6, 0xbb, 0xbb, 0xcd, 0xce, 0xd4,
-       0xec, 0xde, 0xf3, 0xe4, 0xc4, 0xe1, 0xe0, 0xaf, 0xc7, 0xea, 0xbc, 0xae,
-       0xe1, 0xd6, 0xb6, 0xc7, 0xcc, 0xae, 0xa2, 0xab, 0x9a, 0x00, 0x00, 0x00,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0x00, 0x00, 0x00, 0xe3, 0xab, 0xc0, 0xe6, 0xa3, 0xa7, 0xdf, 0xba, 0xa8,
-       0xcf, 0xc5, 0xa9, 0xbd, 0xc2, 0xae, 0xad, 0xb4, 0xaf, 0xc6, 0xc9, 0xcd,
-       0xec, 0xde, 0xf3, 0xe2, 0xbf, 0xdc, 0xe7, 0xa9, 0xb4, 0xe7, 0xd6, 0xb8,
-       0xc7, 0xcc, 0xae, 0xac, 0xb6, 0xa6, 0x9d, 0xa8, 0x9f, 0x00, 0x00, 0x00,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00,
-       0xd9, 0xaf, 0xcf, 0xe1, 0xb4, 0xd2, 0xe2, 0xb0, 0xcb, 0xe4, 0xa9, 0xbb,
-       0xe2, 0xb2, 0xa6, 0xcf, 0xc5, 0xa9, 0x6a, 0x6a, 0x6a, 0x0d, 0x0d, 0x0d,
-       0x0d, 0x0d, 0x0d, 0x6a, 0x6a, 0x6a, 0xed, 0xcd, 0xb6, 0xc7, 0xcc, 0xae,
-       0xa6, 0xb1, 0xa3, 0x98, 0xa2, 0x9c, 0x8f, 0x97, 0x96, 0x7e, 0x84, 0x85,
-       0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00,
-       0xe8, 0xc6, 0xe7, 0xe5, 0xc2, 0xe3, 0xe3, 0xbd, 0xdd, 0xe1, 0xb6, 0xd5,
-       0xe2, 0xb0, 0xcb, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x6a, 0x6a, 0x6a, 0x9d, 0xa8, 0x9f,
-       0x8f, 0x97, 0x96, 0x8b, 0x90, 0x92, 0x97, 0x9e, 0xa2, 0xa0, 0xa7, 0xae,
-       0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00,
-       0xe7, 0xd3, 0xed, 0xe8, 0xd1, 0xed, 0xe8, 0xce, 0xec, 0xe9, 0xcc, 0xeb,
-       0xe8, 0xc6, 0xe7, 0x0d, 0x0d, 0x0d, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x0d, 0x0d, 0x0d, 0x97, 0x9e, 0xa2,
-       0xa7, 0xae, 0xb7, 0xb2, 0xb6, 0xc5, 0xba, 0xbc, 0xce, 0xbf, 0xbe, 0xd3,
-       0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00,
-       0xe9, 0xdf, 0xf0, 0xe9, 0xdf, 0xf0, 0xe9, 0xdf, 0xf0, 0xe9, 0xdf, 0xf0,
-       0xe9, 0xdf, 0xf0, 0x0d, 0x0d, 0x0d, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x0d, 0x0d, 0x0d, 0xe1, 0xd2, 0xf7,
-       0xe1, 0xd2, 0xf7, 0xe1, 0xd2, 0xf7, 0xe1, 0xd2, 0xf7, 0xe1, 0xd2, 0xf7,
-       0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00,
-       0xca, 0xc7, 0xd2, 0xc5, 0xc4, 0xcd, 0xbf, 0xbf, 0xc7, 0xb8, 0xb9, 0xc0,
-       0xae, 0xaf, 0xb6, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x6a, 0x6a, 0x6a, 0xd5, 0xa8, 0xe1,
-       0xd8, 0xb2, 0xe9, 0xd9, 0xb8, 0xed, 0xdb, 0xbd, 0xf0, 0xdc, 0xbf, 0xf1,
-       0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00,
-       0xa4, 0xa6, 0xac, 0xa8, 0xaa, 0xaf, 0xa0, 0xa6, 0xa8, 0x98, 0x9e, 0x9c,
-       0xa1, 0xa8, 0x9e, 0xb1, 0xb6, 0xa1, 0x6a, 0x6a, 0x6a, 0x0d, 0x0d, 0x0d,
-       0x0d, 0x0d, 0x0d, 0x6a, 0x6a, 0x6a, 0xc0, 0x8c, 0xad, 0xcc, 0x90, 0xb5,
-       0xd3, 0x94, 0xca, 0xd6, 0xa2, 0xdb, 0xd5, 0xa8, 0xe1, 0xcf, 0xa7, 0xdf,
-       0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0x00, 0x00, 0x00, 0x98, 0x9f, 0x9b, 0xa1, 0xa8, 0x9e, 0xac, 0xb3, 0xa0,
-       0xb9, 0xb9, 0xa4, 0xd0, 0xb8, 0xa8, 0xc5, 0xb5, 0xb8, 0xb6, 0xbb, 0xad,
-       0xe3, 0xd7, 0xb5, 0xdd, 0xb4, 0xa9, 0xcb, 0x89, 0xac, 0xc0, 0x8c, 0xad,
-       0xc8, 0x91, 0xb5, 0xd1, 0x8d, 0xb7, 0xd3, 0x94, 0xca, 0x00, 0x00, 0x00,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0x00, 0x00, 0x00, 0xa1, 0xa7, 0x98, 0xb1, 0xb6, 0xa1, 0xbd, 0xb9, 0xa5,
-       0xd0, 0xb8, 0xa8, 0xca, 0xb5, 0xb7, 0xb8, 0xb1, 0xb1, 0xc2, 0xc8, 0xb2,
-       0xe3, 0xd7, 0xb5, 0xe1, 0xbf, 0xaf, 0xdb, 0x92, 0x9a, 0xbe, 0x82, 0xa6,
-       0xc0, 0x8c, 0xad, 0xc8, 0x91, 0xb4, 0xc7, 0x8b, 0xb0, 0x00, 0x00, 0x00,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0xbc, 0xb6, 0xa1, 0xd0, 0xb8, 0xa8,
-       0xcd, 0xb6, 0xb7, 0xc0, 0xb4, 0xb5, 0xb1, 0xb1, 0xaa, 0xca, 0xd1, 0xb4,
-       0xe3, 0xd7, 0xb5, 0xe2, 0xc1, 0xb0, 0xdb, 0xa8, 0xa3, 0xd2, 0x8a, 0xa9,
-       0xb7, 0x7e, 0xa2, 0xbd, 0x89, 0xa9, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0xc9, 0xaf, 0xaf,
-       0xc5, 0xb5, 0xb8, 0xb8, 0xb1, 0xb1, 0xb6, 0xbb, 0xad, 0xd0, 0xd6, 0xb5,
-       0xe3, 0xd7, 0xb5, 0xe2, 0xbf, 0xaf, 0xdd, 0xb4, 0xa9, 0xdb, 0x92, 0x9a,
-       0xc6, 0x84, 0xa7, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0xac, 0xaa, 0xa6, 0xbd, 0xc3, 0xb0, 0xd2, 0xd7, 0xb5,
-       0xe3, 0xd7, 0xb5, 0xe2, 0xbf, 0xae, 0xdb, 0xb6, 0xa8, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
-       0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff
+
+typedef struct _LoadContext LoadContext;
+
+struct _LoadContext
+{
+  gchar *filename;
+  GtkWidget *window;
+  GdkPixbufLoader *pixbuf_loader;
+  guint load_timeout;
+  FILE* image_stream;
 };
 
 static void
-quit_func (GtkWidget *widget, gpointer dummy)
+destroy_context (gpointer data)
 {
-       gtk_main_quit ();
+  LoadContext *lc = data;
+
+  g_free (lc->filename);
+  
+  if (lc->load_timeout)
+    g_source_remove (lc->load_timeout);
+
+  if (lc->image_stream)
+    fclose (lc->image_stream);
+
+  if (lc->pixbuf_loader)
+    {
+      gdk_pixbuf_loader_close (lc->pixbuf_loader, NULL);
+      g_object_unref (G_OBJECT (lc->pixbuf_loader));
+    }
+  
+  g_free (lc);
 }
 
-static void
-expose_func (GtkWidget *drawing_area, GdkEventExpose *event, gpointer data)
+static LoadContext*
+get_load_context (GtkWidget *image)
 {
-       GdkPixbuf *pixbuf;
-
-       pixbuf = (GdkPixbuf *)gtk_object_get_data(GTK_OBJECT(drawing_area), "pixbuf");
-
-       if (gdk_pixbuf_get_has_alpha (pixbuf)) {
-               gdk_draw_rgb_32_image (drawing_area->window,
-                                      drawing_area->style->black_gc,
-                                      event->area.x, event->area.y, 
-                                      event->area.width, 
-                                      event->area.height,
-                                      GDK_RGB_DITHER_MAX, 
-                                      gdk_pixbuf_get_pixels (pixbuf) 
-                                      + (event->area.y * gdk_pixbuf_get_rowstride (pixbuf)) 
-                                      + (event->area.x * gdk_pixbuf_get_n_channels (pixbuf)),
-                                      gdk_pixbuf_get_rowstride (pixbuf));
-       } else {
-               gdk_draw_rgb_image (drawing_area->window,
-                                   drawing_area->style->white_gc,
-                                   event->area.x, event->area.y, 
-                                   event->area.width, 
-                                   event->area.height,
-                                   GDK_RGB_DITHER_NORMAL,
-                                   gdk_pixbuf_get_pixels (pixbuf)
-                                   + (event->area.y * gdk_pixbuf_get_rowstride (pixbuf))
-                                   + (event->area.x * gdk_pixbuf_get_n_channels (pixbuf)),
-                                   gdk_pixbuf_get_rowstride (pixbuf));
-       }
+  LoadContext *lc;
+
+  lc = g_object_get_data (G_OBJECT (image), "lc");
+
+  if (lc == NULL)
+    {
+      lc = g_new0 (LoadContext, 1);
+
+      g_object_set_data_full (G_OBJECT (image),        
+                              "lc",
+                              lc,
+                              destroy_context);
+    }
+
+  return lc;
 }
 
 static void
-config_func (GtkWidget *drawing_area, GdkEventConfigure *event, gpointer data)
+progressive_prepared_callback (GdkPixbufLoader* loader,
+                               gpointer         data)
 {
-       GdkPixbuf *pixbuf;
-    
-       pixbuf = (GdkPixbuf *)gtk_object_get_data(GTK_OBJECT(drawing_area), "pixbuf");
+  GdkPixbuf* pixbuf;
+  GtkWidget* image;
 
-#if 0
-       if (((event->width) != gdk_pixbuf_get_width (pixbuf)) ||
-           ((event->height) != gdk_pixbuf_get_height (pixbuf)))
-               gdk_pixbuf_scale(pixbuf, event->width, event->height);
-#endif
+  image = GTK_WIDGET (data);
+    
+  pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
+
+  /* Avoid displaying random memory contents, since the pixbuf
+   * isn't filled in yet.
+   */
+  gdk_pixbuf_fill (pixbuf, 0xaaaaaaff);
+
+  /* Could set the pixbuf instead, if we only wanted to display
+   * static images.
+   */
+  gtk_image_set_from_animation (GTK_IMAGE (image),
+                                gdk_pixbuf_loader_get_animation (loader));
 }
 
-static GtkWidget*
-new_testrgb_window (GdkPixbuf *pixbuf, gchar *title)
+static void
+progressive_updated_callback (GdkPixbufLoader* loader,
+                              gint x, gint y, gint width, gint height,
+                              gpointer data)
 {
-       GtkWidget *window;
-       GtkWidget *vbox;
-       GtkWidget *temp_box;
-       GtkWidget *button;
-       GtkWidget *drawing_area;
-       gint w, h;
-       w = gdk_pixbuf_get_width (pixbuf);
-       h = gdk_pixbuf_get_height (pixbuf);
-
-       window = gtk_widget_new (gtk_window_get_type (),
-                                "GtkObject::user_data", NULL,
-                                "GtkWindow::type", GTK_WINDOW_TOPLEVEL,
-                                "GtkWindow::title", "testrgb",
-                                "GtkWindow::allow_shrink", TRUE,
-                                NULL);
-       gtk_signal_connect (GTK_OBJECT (window), "destroy",
-                           (GtkSignalFunc) quit_func, NULL);
-
-       vbox = gtk_vbox_new (FALSE, 0);
-
-       if (title)
-               gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (title),
-                                   TRUE, TRUE, 0);
-
-       drawing_area = gtk_drawing_area_new ();
-
-       temp_box = gtk_hbox_new (FALSE, 0);
-       gtk_widget_set_usize (GTK_WIDGET (drawing_area), w, h);
-       gtk_box_pack_start (GTK_BOX (temp_box), drawing_area, FALSE, FALSE, 0);
-       gtk_box_pack_start (GTK_BOX (vbox), temp_box, FALSE, FALSE, 0);
-       
-
-       gtk_signal_connect (GTK_OBJECT(drawing_area), "expose_event",
-                           GTK_SIGNAL_FUNC(expose_func), NULL);
-       gtk_signal_connect (GTK_OBJECT(drawing_area), "configure_event",
-                           GTK_SIGNAL_FUNC (config_func), NULL);
-
-       gtk_object_set_data (GTK_OBJECT(drawing_area), "pixbuf", pixbuf);
-
-       gtk_widget_show (drawing_area);
-
-       button = gtk_button_new_with_label ("Quit");
-       gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
-       gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
-                                  (GtkSignalFunc) gtk_widget_destroy,
-                                  GTK_OBJECT (window));
-
-       gtk_widget_show (button);
-
-       gtk_container_add (GTK_CONTAINER (window), vbox);
-       gtk_widget_show_all (vbox);
-
-       gtk_widget_show (window);
-
-        return window;
+  GtkWidget* image;
+  
+  image = GTK_WIDGET (data);
+
+  /* We know the pixbuf inside the GtkImage has changed, but the image
+   * itself doesn't know this; so queue a redraw.  If we wanted to be
+   * really efficient, we could use a drawing area or something
+   * instead of a GtkImage, so we could control the exact position of
+   * the pixbuf on the display, then we could queue a draw for only
+   * the updated area of the image.
+   */
+
+  /* We only really need to redraw if the image's animation iterator
+   * is gdk_pixbuf_animation_iter_on_currently_loading_frame(), but
+   * who cares.
+   */
+  
+  gtk_widget_queue_draw (image);
 }
 
-#if 0
-
 static gint
-update_timeout(gpointer data)
+progressive_timeout (gpointer data)
 {
-        ProgressFileStatus *status = data;
-       gboolean done;
-
-       done = TRUE;
-       if (!feof(status->imagefile)) {
-               gint nbytes;
-
-               nbytes = fread(status->buf, 1, status->readlen, 
-                              status->imagefile);
-
-               done = !gdk_pixbuf_loader_write (GDK_PIXBUF_LOADER (status->loader), status->buf, nbytes);
-                       
-       }
-
-       if (done) {
-                gtk_widget_queue_draw(*status->rgbwin);
-               gdk_pixbuf_loader_close (GDK_PIXBUF_LOADER (status->loader));
-               g_object_destroy (G_OBJECT(status->loader));
-               fclose (status->imagefile);
-               g_free (status->buf);
-       }
+  GtkWidget *image;
+  LoadContext *lc;
+  
+  image = GTK_WIDGET (data);
+  lc = get_load_context (image);
+  
+  /* This shows off fully-paranoid error handling, so looks scary.
+   * You could factor out the error handling code into a nice separate
+   * function to make things nicer.
+   */
+  
+  if (lc->image_stream)
+    {
+      size_t bytes_read;
+      guchar buf[256];
+      GError *error = NULL;
+      
+      bytes_read = fread (buf, 1, 256, lc->image_stream);
+
+      if (ferror (lc->image_stream))
+        {
+          GtkWidget *dialog;
+          
+          dialog = gtk_message_dialog_new (GTK_WINDOW (lc->window),
+                                           GTK_DIALOG_DESTROY_WITH_PARENT,
+                                           GTK_MESSAGE_ERROR,
+                                           GTK_BUTTONS_CLOSE,
+                                           "Failure reading image file 'alphatest.png': %s",
+                                           g_strerror (errno));
+
+          gtk_signal_connect (GTK_OBJECT (dialog),
+                              "response",
+                              GTK_SIGNAL_FUNC (gtk_widget_destroy),
+                              NULL);
+
+          fclose (lc->image_stream);
+          lc->image_stream = NULL;
+
+          gtk_widget_show (dialog);
+          
+          lc->load_timeout = 0;
+
+          return FALSE; /* uninstall the timeout */
+        }
+
+      if (!gdk_pixbuf_loader_write (lc->pixbuf_loader,
+                                    buf, bytes_read,
+                                    &error))
+        {
+          GtkWidget *dialog;
+          
+          dialog = gtk_message_dialog_new (GTK_WINDOW (lc->window),
+                                           GTK_DIALOG_DESTROY_WITH_PARENT,
+                                           GTK_MESSAGE_ERROR,
+                                           GTK_BUTTONS_CLOSE,
+                                           "Failed to load image: %s",
+                                           error->message);
 
-       return !done;
+          g_error_free (error);
+          
+          gtk_signal_connect (GTK_OBJECT (dialog),
+                              "response",
+                              GTK_SIGNAL_FUNC (gtk_widget_destroy),
+                              NULL);
+
+          fclose (lc->image_stream);
+          lc->image_stream = NULL;
+          
+          gtk_widget_show (dialog);
+
+          lc->load_timeout = 0;
+
+          return FALSE; /* uninstall the timeout */
+        }
+
+      if (feof (lc->image_stream))
+        {
+          fclose (lc->image_stream);
+          lc->image_stream = NULL;
+
+          /* Errors can happen on close, e.g. if the image
+           * file was truncated we'll know on close that
+           * it was incomplete.
+           */
+          error = NULL;
+          if (!gdk_pixbuf_loader_close (lc->pixbuf_loader,
+                                        &error))
+            {
+              GtkWidget *dialog;
+              
+              dialog = gtk_message_dialog_new (GTK_WINDOW (lc->window),
+                                               GTK_DIALOG_DESTROY_WITH_PARENT,
+                                               GTK_MESSAGE_ERROR,
+                                               GTK_BUTTONS_CLOSE,
+                                               "Failed to load image: %s",
+                                               error->message);
+              
+              g_error_free (error);
+              
+              gtk_signal_connect (GTK_OBJECT (dialog),
+                                  "response",
+                                  GTK_SIGNAL_FUNC (gtk_widget_destroy),
+                                  NULL);
+              
+              gtk_widget_show (dialog);
+
+              g_object_unref (G_OBJECT (lc->pixbuf_loader));
+              lc->pixbuf_loader = NULL;
+              
+              lc->load_timeout = 0;
+              
+              return FALSE; /* uninstall the timeout */
+            }
+          
+          g_object_unref (G_OBJECT (lc->pixbuf_loader));
+          lc->pixbuf_loader = NULL;
+        }
+    }
+  else
+    {
+      lc->image_stream = fopen (lc->filename, "r");
+
+      if (lc->image_stream == NULL)
+        {
+          GtkWidget *dialog;
+          
+          dialog = gtk_message_dialog_new (GTK_WINDOW (lc->window),
+                                           GTK_DIALOG_DESTROY_WITH_PARENT,
+                                           GTK_MESSAGE_ERROR,
+                                           GTK_BUTTONS_CLOSE,
+                                           "Unable to open image file '%s': %s",
+                                           lc->filename,
+                                           g_strerror (errno));
+
+          gtk_signal_connect (GTK_OBJECT (dialog),
+                              "response",
+                              GTK_SIGNAL_FUNC (gtk_widget_destroy),
+                              NULL);
+          
+          gtk_widget_show (dialog);
+
+          lc->load_timeout = 0;
+
+          return FALSE; /* uninstall the timeout */
+        }
+
+      if (lc->pixbuf_loader)
+        {
+          gdk_pixbuf_loader_close (lc->pixbuf_loader, NULL);
+          g_object_unref (G_OBJECT (lc->pixbuf_loader));
+          lc->pixbuf_loader = NULL;
+        }
+      
+      lc->pixbuf_loader = gdk_pixbuf_loader_new ();
+      
+      g_signal_connect_data (G_OBJECT (lc->pixbuf_loader),
+                             "area_prepared",
+                             G_CALLBACK (progressive_prepared_callback),
+                             image,
+                             NULL, FALSE, FALSE);
+      
+      g_signal_connect_data (G_OBJECT (lc->pixbuf_loader),
+                             "area_updated",
+                             G_CALLBACK (progressive_updated_callback),
+                             image,
+                             NULL, FALSE, FALSE);
+    }
+
+  /* leave timeout installed */
+  return TRUE;
 }
 
 static void
-progressive_prepared_callback(GdkPixbufLoader* loader, gpointer data)
+start_progressive_loading (GtkWidget *image)
 {
-        GtkWidget** retloc = data;
-        GdkPixbuf* pixbuf;
-
-        pixbuf = gdk_pixbuf_loader_get_pixbuf(loader);
-        g_assert(pixbuf != NULL);
-
-        gdk_pixbuf_ref(pixbuf); /* for the RGB window */
-
-        *retloc = new_testrgb_window(pixbuf, "Progressive");
-
-        return;
+  LoadContext *lc;
+
+  lc = get_load_context (image);
+  
+  /* This is obviously totally contrived (we slow down loading
+   * on purpose to show how incremental loading works).
+   * The real purpose of incremental loading is the case where
+   * you are reading data from a slow source such as the network.
+   * The timeout simply simulates a slow data source by inserting
+   * pauses in the reading process.
+   */
+  lc->load_timeout = g_timeout_add (100,
+                                    progressive_timeout,
+                                    image);
 }
 
+static GtkWidget *
+do_image (const char *filename)
+{
+  GtkWidget *frame;
+  GtkWidget *vbox;
+  GtkWidget *image;
+  GtkWidget *label;
+  GtkWidget *align;
+  GtkWidget *window;
+  gchar *str, *escaped;
+  LoadContext *lc;
+  
+  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_window_set_title (GTK_WINDOW (window), "Image Loading");
+
+  gtk_container_set_border_width (GTK_CONTAINER (window), 8);
+
+  vbox = gtk_vbox_new (FALSE, 8);
+  gtk_container_set_border_width (GTK_CONTAINER (vbox), 8);
+  gtk_container_add (GTK_CONTAINER (window), vbox);
+
+  label = gtk_label_new (NULL);
+  gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
+  escaped = g_markup_escape_text (filename, -1);
+  str = g_strdup_printf ("Progressively loading: <b>%s</b>", escaped);
+  gtk_label_set_markup (GTK_LABEL (label),
+                        str);
+  g_free (escaped);
+  g_free (str);
+  
+  gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
+      
+  frame = gtk_frame_new (NULL);
+  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
+  /* The alignment keeps the frame from growing when users resize
+   * the window
+   */
+  align = gtk_alignment_new (0.5, 0.5, 0, 0);
+  gtk_container_add (GTK_CONTAINER (align), frame);
+  gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 0);      
+
+  image = gtk_image_new_from_pixbuf (NULL);
+  gtk_container_add (GTK_CONTAINER (frame), image);
+
+  lc = get_load_context (image);
+
+  lc->window = window;
+  lc->filename = g_strdup (filename);
+  
+  start_progressive_loading (image);
+
+  gtk_widget_show_all (window);
+
+  return window;
+}
 
 static void
-progressive_updated_callback(GdkPixbufLoader* loader, guint x, guint y, guint width, guint height, gpointer data)
+do_nonprogressive (const gchar *filename)
 {
-        GtkWidget** window_loc = data;
-
-/*     g_print ("progressive_updated_callback:\n\t%d\t%d\t%d\t%d\n", x, y, width, height); */
-
-        if (*window_loc != NULL)
-                gtk_widget_queue_draw_area(*window_loc,
-                                          x, y, width, height);
-
-        return;
+  GtkWidget *frame;
+  GtkWidget *vbox;
+  GtkWidget *image;
+  GtkWidget *label;
+  GtkWidget *align;
+  GtkWidget *window;
+  gchar *str, *escaped;
+  
+  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_window_set_title (GTK_WINDOW (window), "Animation");
+
+  gtk_container_set_border_width (GTK_CONTAINER (window), 8);
+
+  vbox = gtk_vbox_new (FALSE, 8);
+  gtk_container_set_border_width (GTK_CONTAINER (vbox), 8);
+  gtk_container_add (GTK_CONTAINER (window), vbox);
+
+  label = gtk_label_new (NULL);
+  gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
+  escaped = g_markup_escape_text (filename, -1);
+  str = g_strdup_printf ("Loaded from file: <b>%s</b>", escaped);
+  gtk_label_set_markup (GTK_LABEL (label),
+                        str);
+  g_free (escaped);
+  g_free (str);
+  
+  gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
+      
+  frame = gtk_frame_new (NULL);
+  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
+  /* The alignment keeps the frame from growing when users resize
+   * the window
+   */
+  align = gtk_alignment_new (0.5, 0.5, 0, 0);
+  gtk_container_add (GTK_CONTAINER (align), frame);
+  gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 0);      
+
+  image = gtk_image_new_from_file (filename);
+  gtk_container_add (GTK_CONTAINER (frame), image);
+
+  gtk_widget_show_all (window);
 }
 
-#endif
-
-static int readlen = 4096;
-
-extern void pixbuf_init();
-
 int
-main (int argc, char **argv)
+main (int    argc,
+      char **argv)
 {
-       int i;
-       int found_valid = FALSE;
-
-       GdkPixbufAnimation *animation;
-
-       pixbuf_init ();
-
-       gtk_init (&argc, &argv);
-
-       gdk_rgb_set_verbose (TRUE);
-
-       gdk_rgb_init ();
-
-       gtk_widget_set_default_colormap (gdk_rgb_get_cmap ());
-
-       {
-               char *tbf_readlen = getenv("TBF_READLEN");
-               if(tbf_readlen) readlen = atoi(tbf_readlen);
-       }
-
-       {
-               char *tbf_bps = getenv("TBF_KBPS");
-               guint bps;
-
-               if (tbf_bps) {
-                       bps = atoi(tbf_bps);
-                       g_print ("Simulating %d kBytes/sec\n", bps);
-                       readlen = (bps*1024)/10;
-               }
-       }
-
-       i = 1;
-       if (argc == 1) {
-               g_print ("USAGE:  testanimation FILE1 ...\n");
-               return 0;
-       } else {
-               for (i = 1; i < argc; i++) {
-                        GError *error;
+  gint i;
+  
+  gtk_init (&argc, &argv);
+
+  i = 1;
+  while (i < argc)
+    {
+      do_image (argv[i]);
+      do_nonprogressive (argv[i]);
+      
+      ++i;
+    }
+
+  gtk_main ();
+  
+  return 0;
+}
 
-                        error = NULL;
-                       animation = gdk_pixbuf_animation_new_from_file (argv[i],
-                                                                        &error);
 
-                        if (animation == NULL) {
-                                g_warning ("Failed to load animation: %s",
-                                           error->message);
-                                g_error_free (error);
-                        }
-                        
-                       if (animation) {
-                               gint i = 0;
-                               GList *listptr;
-                               for (listptr = gdk_pixbuf_animation_get_frames (animation);
-                                    listptr;
-                                    listptr = listptr->next) {
-                                       GdkPixbufFrame *frame;
-                                       GdkPixbuf *pixbuf;
-                                       gchar *title;
-
-                                       frame = listptr->data;
-                                       pixbuf = gdk_pixbuf_frame_get_pixbuf (frame);
-
-                                       title = g_strdup_printf ("Frame %d", i);
-                                       g_print ("Frame %d  x:%d y:%d width:%d height:%d\n",
-                                                i,
-                                                gdk_pixbuf_frame_get_x_offset (frame),
-                                                gdk_pixbuf_frame_get_y_offset (frame),
-                                                gdk_pixbuf_get_width (pixbuf),
-                                                gdk_pixbuf_get_height (pixbuf));
-                                       new_testrgb_window (pixbuf, title);
-                                       g_free (title);
-                                       i++;
-                               }
-                               found_valid = TRUE;
-                       }
-               }
-#if 0
-                {
-                        GtkWidget* rgb_window = NULL;
-                       ProgressFileStatus   status;
-                       GdkPixbufLoader *pixbuf_loader;
-
-                        pixbuf_loader = gdk_pixbuf_loader_new ();
-                       status.loader = pixbuf_loader;
-
-                       status.rgbwin = &rgb_window;
-
-                       status.buf = g_malloc (readlen);
-                        g_signal_connect_data(G_OBJECT(pixbuf_loader),
-                                              "area_prepared",
-                                              GTK_SIGNAL_FUNC(progressive_prepared_callback),
-                                              &rgb_window,
-                                              NULL, FALSE, FALSE);
-
-                        g_signal_connect_data(G_OBJECT(pixbuf_loader),
-                                              "area_updated",
-                                              GTK_SIGNAL_FUNC(progressive_updated_callback),
-                                              &rgb_window,
-                                              NULL, FALSE, FALSE);
-
-                       
-                        status.imagefile = fopen (argv[1], "r");
-                        g_assert (status.imagefile != NULL);
-
-                       status.readlen = readlen;
-
-                        status.timeout = gtk_timeout_add(100, update_timeout, &status);
-                }
-#endif
-       }
-
-       if (found_valid)
-               gtk_main ();
-
-       return 0;
-}
index 9d29563171acda771fb1ed9542cd4c6574395343..d59095b6928fc112eed7b934873df269053c7a26 100644 (file)
@@ -1,4 +1,8 @@
-2001-04-20  Havoc Pennington  <hp@redhat.com>
+2001-04-26  Havoc Pennington  <hp@redhat.com>
+
+       * gtk/tmpl/gtkimage.sgml: document GtkImageType
+
+       * gtk/gtk-sections.txt: GtkImageType is public
 
        * gdk/tmpl/images.sgml: add warning about gtk_image_new_bitmap
 
index 9e9d4b2ff5dc56046d8abe8183612b9275c53baf..f13b066aca36663d38f3244d25c22b9a2eaa242d 100644 (file)
@@ -2,15 +2,17 @@
 Animations
 
 <!-- ##### SECTION Short_Description ##### -->
-Animations as multi-frame structures.
+Animated images.
 
 <!-- ##### SECTION Long_Description ##### -->
   <para>
-    The &gdk-pixbuf; library provides a simple mechanism to load and
-    represent animations, primarily animated GIF files.  Animations
-    are represented as lists of #GdkPixbufFrame structures.  Each
-    frame structure contains a #GdkPixbuf structure and information
-    about the frame's overlay mode and duration.
+    The &gdk-pixbuf; library provides a simple mechanism to load and represent
+    animations. An animation is conceptually a series of frames to be displayed
+    over time. Each frame is the same size. The animation may not be represented
+    as a series of frames internally; for example, it may be stored as a 
+    sprite and instructions for moving the sprite around a background. To display 
+    an animation you don't need to understand its representation, however; you just
+    ask &gdk-pixbuf; what should be displayed at a given point in time. 
   </para>
 
 <!-- ##### SECTION See_Also ##### -->
@@ -18,34 +20,9 @@ Animations as multi-frame structures.
     #GdkPixbufLoader
   </para>
 
-<!-- ##### ENUM GdkPixbufFrameAction ##### -->
-  <para>
-    Each animation frame can have several things happen to it when the
-    next frame is displayed.  The #GdkPixbufFrameAction determines
-    this.  These are essentially the overlay modes supported by GIF
-    animations.
-  </para>
-
-@GDK_PIXBUF_FRAME_RETAIN: The previous image should remain displayed,
-and will potentially be occluded by the new frame.
-@GDK_PIXBUF_FRAME_DISPOSE: The animation will be reverted to the state
-before the frame was shown.
-@GDK_PIXBUF_FRAME_REVERT: The animation will be reverted to the first
-frame.
-
-<!-- ##### STRUCT GdkPixbufFrame ##### -->
-  <para>
-    This structure describes a frame in a #GdkPixbufAnimation.  Each
-    frame consists of a #GdkPixbuf, an offset of the frame within the
-    animation's bounding box, a duration, and an overlay mode or
-    action.
-  </para>
-
-
 <!-- ##### STRUCT GdkPixbufAnimation ##### -->
   <para>
-    This structure describes an animation, which is represented as a
-    list of #GdkPixbufFrame structures.
+    This object describes an animation.
   </para>
 
 
@@ -76,15 +53,6 @@ frame.
 @animation: 
 
 
-<!-- ##### FUNCTION gdk_pixbuf_animation_get_frames ##### -->
-<para>
-
-</para>
-
-@animation: 
-@Returns: 
-
-
 <!-- ##### FUNCTION gdk_pixbuf_animation_get_width ##### -->
 <para>
 
@@ -94,15 +62,6 @@ frame.
 @Returns: 
 
 
-<!-- ##### FUNCTION gdk_pixbuf_animation_get_num_frames ##### -->
-<para>
-
-</para>
-
-@animation: 
-@Returns: 
-
-
 <!-- ##### FUNCTION gdk_pixbuf_animation_get_height ##### -->
 <para>
 
@@ -112,70 +71,3 @@ frame.
 @Returns: 
 
 
-<!-- ##### FUNCTION gdk_pixbuf_frame_copy ##### -->
-<para>
-
-</para>
-
-@src: 
-@Returns: 
-
-
-<!-- ##### FUNCTION gdk_pixbuf_frame_free ##### -->
-<para>
-
-</para>
-
-@frame: 
-
-
-<!-- ##### FUNCTION gdk_pixbuf_frame_get_pixbuf ##### -->
-<para>
-
-</para>
-
-@frame: 
-@Returns: 
-
-
-<!-- ##### FUNCTION gdk_pixbuf_frame_get_action ##### -->
-<para>
-
-</para>
-
-@frame: 
-@Returns: 
-
-
-<!-- ##### FUNCTION gdk_pixbuf_frame_get_y_offset ##### -->
-<para>
-
-</para>
-
-@frame: 
-@Returns: 
-
-
-<!-- ##### FUNCTION gdk_pixbuf_frame_get_delay_time ##### -->
-<para>
-
-</para>
-
-@frame: 
-@Returns: 
-
-
-<!-- ##### FUNCTION gdk_pixbuf_frame_get_x_offset ##### -->
-<para>
-
-</para>
-
-@frame: 
-@Returns: <!--
-Local variables:
-mode: sgml
-sgml-parent-document: ("../gdk-pixbuf.sgml" "book" "refsect2" "")
-End:
--->
-
-
index b2f07bd0ef628ace1cf93fb2a9962f2ac3f30cc9..acdebe537cf2ed4bf4651baf48a8503752fc5f01 100644 (file)
@@ -132,15 +132,6 @@ Application-driven progressive image loading.
 @Returns: 
 
 
-<!-- ##### SIGNAL GdkPixbufLoader::animation-done ##### -->
-  <para>
-    This signal is emitted when an animation is done loading.
-  </para>
-
-@gdkpixbufloader: the object which received the signal.
-<!-- # Unused Parameters # -->
-@loader: Loader which emitted the signal.
-
 <!-- ##### SIGNAL GdkPixbufLoader::area-prepared ##### -->
   <para>
     This signal is emitted when the pixbuf loader has been fed the
@@ -194,15 +185,3 @@ sgml-parent-document: ("../gdk-pixbuf.sgml" "book" "refsect2" "")
 End:
 -->
 
-<!-- ##### SIGNAL GdkPixbufLoader::frame-done ##### -->
-  <para>
-    This signal is emitted when a frame is done loading.  It will be
-    emitted for each frame in an animation data stream.
-  </para>
-
-@gdkpixbufloader: the object which received the signal.
-@arg1: 
-<!-- # Unused Parameters # -->
-@loader: Loader which emitted the signal.
-@frame: Frame which just completed loading.
-
index 563fabb57efebb781cb190cf5fc164ccbd647924..139ee467d3c5e260924e30354c8512a572d0c373 100644 (file)
@@ -28,6 +28,7 @@ Module Interface
 </para>
 
 @pixbuf: 
+@anim: 
 @user_data: 
 
 
@@ -44,24 +45,6 @@ Module Interface
 @user_data: 
 
 
-<!-- ##### USER_FUNCTION ModuleFrameDoneNotifyFunc ##### -->
-<para>
-
-</para>
-
-@frame: 
-@user_data: 
-
-
-<!-- ##### USER_FUNCTION ModuleAnimationDoneNotifyFunc ##### -->
-<para>
-
-</para>
-
-@pixbuf: 
-@user_data: 
-
-
 <!-- ##### STRUCT GdkPixbufModule ##### -->
 <para>
 
index ddd6cd94fbd616e5ff7f4122752de2c7986785ce..4e5b743ff3de9c250e847dd9003420ade388e027 100644 (file)
@@ -967,6 +967,7 @@ GTK_HSEPARATOR_GET_CLASS
 <FILE>gtkimage</FILE>
 <TITLE>GtkImage</TITLE>
 GtkImage
+GtkImageType
 gtk_image_get_icon_set
 gtk_image_get_image
 gtk_image_get_pixbuf
@@ -1002,7 +1003,6 @@ GtkImageImageData
 GtkImagePixbufData
 GtkImagePixmapData
 GtkImageStockData
-GtkImageType
 </SECTION>
 
 <SECTION>
index 4cb131d8ce5a1183a0566f24aadde8373f4bb36b..20397f167d3859e1eb6892c5613737bc8b3bc33a 100644 (file)
@@ -1621,19 +1621,3 @@ fundamental type.
 @window: 
 @Returns: 
 
-<!-- ##### FUNCTION gtk_window_set_decorations_hint ##### -->
-<para>
-
-</para>
-
-@window: 
-@decorations: 
-
-<!-- ##### FUNCTION gtk_window_set_functions_hint ##### -->
-<para>
-
-</para>
-
-@window: 
-@functions: 
-
index 6f8bfdd021efe5ed05c47c5175c1a775ec6814ad..67e5d22ae661e6090a81c82a7db81ae105b1df03 100644 (file)
@@ -28,6 +28,24 @@ below.
 </para>
 
 
+<!-- ##### ENUM GtkImageType ##### -->
+<para>
+Describes the representation stored by a #GtkImage. If you want to get the image
+from the widget, you can only get the currently-stored representation. e.g.  if
+the gtk_image_get_storage_type() returns #GTK_IMAGE_PIXBUF, then you can call
+gtk_image_get_pixbuf() but not gtk_image_get_stock().  For empty images, you can
+request any storage type (call any of the "get" functions), but they will all
+return %NULL values.
+</para>
+
+@GTK_IMAGE_EMPTY: there is no image displayed by the widget
+@GTK_IMAGE_PIXMAP: the widget contains a #GdkPixmap
+@GTK_IMAGE_IMAGE: the widget contains a #GdkImage
+@GTK_IMAGE_PIXBUF: the widget contains a #GdkPixbuf
+@GTK_IMAGE_STOCK: the widget contains a stock icon name
+@GTK_IMAGE_ICON_SET: the widget contains a #GtkIconSet
+@GTK_IMAGE_ANIMATION: 
+
 <!-- ##### FUNCTION gtk_image_get_icon_set ##### -->
 <para>
 
index 178b40392298c4059e35c7c6e505cd0fa52ed528..88a0a4a50768b9125a3501db571c351823709144 100644 (file)
@@ -387,7 +387,6 @@ can define other sizes.
 
 <para>
 It's also possible to use custom icons for a given state, for example:
-You can specify custom icons for specific sizes, as follows:
 <programlisting>
 stock["my-stock-item"] = 
 {
@@ -496,6 +495,7 @@ This can later be composited together with other
 #GtkRcStyle structures to form a #GtkStyle.
 </para>
 
+@parent_instance: 
 @name: 
 @bg_pixmap_name: 
 @font_desc: 
index 877a40d09b9923189cb6cb3380c76f6440cfb22f..3df95306735a7af7792d7000e9cdff9d38684ab3 100644 (file)
@@ -43,7 +43,9 @@ slider.</entry>
 
 <!-- ##### FUNCTION gtk_scale_set_digits ##### -->
 <para>
-Sets the number of decimal places that are displayed in the value.
+Sets the number of decimal places that are displayed in the value.  Also causes
+the value of the adjustment to be rounded off to this number of digits, so the
+retrieved value matches the value the user saw.
 </para>
 
 @scale: a #GtkScale.
@@ -80,6 +82,15 @@ string.
 @Returns: the maximum width needed to display the value string.
 
 
+<!-- ##### SIGNAL GtkScale::format-value ##### -->
+<para>
+
+</para>
+
+@scale: the object which received the signal.
+@arg1: 
+@Returns: 
+
 <!-- ##### ARG GtkScale:digits ##### -->
 <para>
 The number of decimal places that are displayed in the value.
index 1a5a4f3e27e616f7c1cd07d369ee283e3247611f..52c116c2669424ee67fa86a75fde108134a0ac42 100644 (file)
@@ -289,7 +289,7 @@ you don't want a return value.
 the callbacks.
 
 
-<!-- ##### FUNCTION gtk_signal_lookup ##### -->
+<!-- ##### MACRO gtk_signal_lookup ##### -->
 <para>
 Given the name of the signal and the type of object it connects
 to, get the signal's identifying integer.  Emitting the signal
@@ -304,7 +304,7 @@ It also tries the ancestors of the given type.
 @Returns: the signal's identifying number, or 0 if no signal was found.
 
 
-<!-- ##### FUNCTION gtk_signal_name ##### -->
+<!-- ##### MACRO gtk_signal_name ##### -->
 <para>
 Given the signal's identifier, find its name.
 </para>
@@ -381,7 +381,7 @@ an array of GtkArgs instead of using C's varargs mechanism.
 followed by one which is a pointer to the return type.
 
 
-<!-- ##### FUNCTION gtk_signal_emit_stop ##### -->
+<!-- ##### MACRO gtk_signal_emit_stop ##### -->
 <para>
 This function aborts a signal's current emission.
 </para>
@@ -415,7 +415,7 @@ except it will lookup the signal id for you.
 @name: the name of the signal you wish to stop.
 
 
-<!-- ##### FUNCTION gtk_signal_connect ##### -->
+<!-- ##### MACRO gtk_signal_connect ##### -->
 <para>
 Attach a function pointer and user data to a signal for
 a particular object.
@@ -467,7 +467,7 @@ is getting pressed, this is that button.
 @d: 
 
 
-<!-- ##### FUNCTION gtk_signal_connect_after ##### -->
+<!-- ##### MACRO gtk_signal_connect_after ##### -->
 <para>
 Attach a function pointer and user data to a signal
 so that this handler will be called after the other handlers.
@@ -485,7 +485,7 @@ so that this handler will be called after the other handlers.
 @d: 
 
 
-<!-- ##### FUNCTION gtk_signal_connect_object ##### -->
+<!-- ##### MACRO gtk_signal_connect_object ##### -->
 <para>
 This function is for registering a callback that will
 call another object's callback.  That is,
@@ -520,7 +520,7 @@ really pass any gpointer as the #slot_object .)
 @d: 
 
 
-<!-- ##### FUNCTION gtk_signal_connect_object_after ##### -->
+<!-- ##### MACRO gtk_signal_connect_object_after ##### -->
 <para>
 Attach a signal hook to a signal, passing in an alternate
 object as the first parameter, and guaranteeing 
@@ -626,7 +626,7 @@ should signal the removal of this signal.
 @name: name of the signal.
 
 
-<!-- ##### FUNCTION gtk_signal_disconnect ##### -->
+<!-- ##### MACRO gtk_signal_disconnect ##### -->
 <para>
 Destroy a user-defined handler connection.
 </para>
@@ -635,7 +635,7 @@ Destroy a user-defined handler connection.
 @handler_id: the connection id.
 
 
-<!-- ##### FUNCTION gtk_signal_disconnect_by_func ##### -->
+<!-- ##### MACRO gtk_signal_disconnect_by_func ##### -->
 <para>
 Destroy all connections for a particular object, with
 the given function-pointer and user-data.
@@ -650,7 +650,7 @@ the given function-pointer and user-data.
 @d: 
 
 
-<!-- ##### FUNCTION gtk_signal_disconnect_by_data ##### -->
+<!-- ##### MACRO gtk_signal_disconnect_by_data ##### -->
 <para>
 Destroy all connections for a particular object, with
 the given user-data.
@@ -663,7 +663,7 @@ the given user-data.
 @d: 
 
 
-<!-- ##### FUNCTION gtk_signal_handler_block ##### -->
+<!-- ##### MACRO gtk_signal_handler_block ##### -->
 <para>
 Prevent an user-defined handler from being invoked.  All other
 signal processing will go on as normal, but this particular
@@ -674,7 +674,7 @@ handler will ignore it.
 @handler_id: the connection id.
 
 
-<!-- ##### FUNCTION gtk_signal_handler_block_by_func ##### -->
+<!-- ##### MACRO gtk_signal_handler_block_by_func ##### -->
 <para>
 Prevent a user-defined handler from being invoked, by reference to
 the user-defined handler's function pointer and user data.  (It may result in
@@ -690,7 +690,7 @@ multiple hooks being blocked, if you've called connect multiple times.)
 @d: 
 
 
-<!-- ##### FUNCTION gtk_signal_handler_block_by_data ##### -->
+<!-- ##### MACRO gtk_signal_handler_block_by_data ##### -->
 <para>
 Prevent all user-defined handlers with a certain user data from being invoked.
 </para>
@@ -702,7 +702,7 @@ Prevent all user-defined handlers with a certain user data from being invoked.
 @d: 
 
 
-<!-- ##### FUNCTION gtk_signal_handler_unblock ##### -->
+<!-- ##### MACRO gtk_signal_handler_unblock ##### -->
 <para>
 Undo a block, by connection id.  Note that undoing a block doesn't
 necessarily make the hook callable, because if you block a
@@ -714,7 +714,7 @@ hook twice, you must unblock it twice.
 gtk_signal_connect(), etc.
 
 
-<!-- ##### FUNCTION gtk_signal_handler_unblock_by_func ##### -->
+<!-- ##### MACRO gtk_signal_handler_unblock_by_func ##### -->
 <para>
 Undo a block, by function pointer and data.
 Note that undoing a block doesn't
@@ -731,7 +731,7 @@ hook twice, you must unblock it twice.
 @d: 
 
 
-<!-- ##### FUNCTION gtk_signal_handler_unblock_by_data ##### -->
+<!-- ##### MACRO gtk_signal_handler_unblock_by_data ##### -->
 <para>
 Undo block(s), to all signals for a particular object
 with a particular user-data pointer
@@ -744,7 +744,7 @@ with a particular user-data pointer
 @d: 
 
 
-<!-- ##### FUNCTION gtk_signal_handler_pending ##### -->
+<!-- ##### MACRO gtk_signal_handler_pending ##### -->
 <para>
 Returns a connection id corresponding to a given signal id and object.
 </para>
@@ -766,7 +766,7 @@ handler.
 @b: 
 
 
-<!-- ##### FUNCTION gtk_signal_handler_pending_by_func ##### -->
+<!-- ##### MACRO gtk_signal_handler_pending_by_func ##### -->
 <para>
 Returns a connection id corresponding to a given signal id, object, function
 pointer and user data.
index a78f5ec0081a2fcb5cb3cfe62794a3b03cb43ae3..73abe4c49f89e7db76bbba3e650e95fa5f46aae7 100644 (file)
@@ -41,6 +41,7 @@ Styles
 @mid: 
 @text: 
 @base: 
+@text_aa: 
 @black: 
 @white: 
 @font: 
@@ -54,6 +55,7 @@ Styles
 @mid_gc: 
 @text_gc: 
 @base_gc: 
+@text_aa_gc: 
 @black_gc: 
 @white_gc: 
 @bg_pixmap: 
@@ -504,6 +506,7 @@ Styles
 @style: 
 @window: 
 @state_type: 
+@use_text: 
 @x: 
 @y: 
 @layout: 
@@ -874,6 +877,7 @@ Styles
 @style: 
 @window: 
 @state_type: 
+@use_text: 
 @area: 
 @widget: 
 @detail: 
index 1615165632d8dfd757f6745e1891fb83f7dd1b48..a7d68099e0870ee65121f62b25c88e865b234422 100644 (file)
@@ -378,15 +378,6 @@ types related to the text widget and how they work together.
 @Returns: 
 
 
-<!-- ##### FUNCTION gtk_text_iter_is_first ##### -->
-<para>
-
-</para>
-
-@iter: 
-@Returns: 
-
-
 <!-- ##### FUNCTION gtk_text_iter_forward_char ##### -->
 <para>
 
index be71c7e39dc6f8feb1c2df8e9f0f29565d40b687..7cff611ab87ca3624f8132fca6dc1203e7e22f97 100644 (file)
@@ -58,6 +58,7 @@ Describes a type of line wrapping.
 @justification: 
 @direction: 
 @font: 
+@font_scale: 
 @left_margin: 
 @indent: 
 @right_margin: 
@@ -279,6 +280,11 @@ Font as a #PangoFontDescription.
 
 </para>
 
+<!-- ##### ARG GtkTextTag:scale ##### -->
+<para>
+
+</para>
+
 <!-- ##### ARG GtkTextTag:size-points ##### -->
 <para>
 
@@ -419,6 +425,11 @@ applies to the first character in a paragraph.
 
 </para>
 
+<!-- ##### ARG GtkTextTag:scale-set ##### -->
+<para>
+
+</para>
+
 <!-- ##### ARG GtkTextTag:justification-set ##### -->
 <para>
 
index 6295e2dfa13c7a3966a7f8539ef3509ca5119ff6..e6a3ad7abf01c3cbbc7aaefd9be0a16fdf318e1a 100644 (file)
@@ -560,7 +560,7 @@ Create a new, unique type.
 @type_info: must not be null, and @type_info->type_name must also not be null.
 
 
-<!-- ##### FUNCTION gtk_type_name ##### -->
+<!-- ##### MACRO gtk_type_name ##### -->
 <para>
 </para>
 
@@ -568,7 +568,7 @@ Create a new, unique type.
 @Returns: a pointer to the name of a type, or NULL if it has none.
 
 
-<!-- ##### FUNCTION gtk_type_from_name ##### -->
+<!-- ##### MACRO gtk_type_from_name ##### -->
 <para>
 Get the internal representation of a type given its name.
 </para>
@@ -577,7 +577,7 @@ Get the internal representation of a type given its name.
 @Returns: a GtkType
 
 
-<!-- ##### FUNCTION gtk_type_parent ##### -->
+<!-- ##### MACRO gtk_type_parent ##### -->
 <para>
 
 </para>
@@ -608,7 +608,7 @@ has all the proper initializers called.
 @Returns: gpointer to a GtkTypeObject
 
 
-<!-- ##### FUNCTION gtk_type_is_a ##### -->
+<!-- ##### MACRO gtk_type_is_a ##### -->
 <para>
 Look in the type hierarchy to see if @type has @is_a_type among its
 ancestors.  Do so with a simple lookup, not a loop.
index 6f4ab3766a63535c3ef54f052cce14e7be601929..adab57e9f5c7c41a0231df54f83f65ed1da3eb00 100644 (file)
@@ -393,6 +393,15 @@ it's larger
 @setting: 
 
 
+<!-- ##### FUNCTION gtk_window_set_decorations_hint ##### -->
+<para>
+
+</para>
+
+@window: 
+@decorations: 
+
+
 <!-- ##### FUNCTION gtk_window_set_frame_dimensions ##### -->
 <para>
 
@@ -405,6 +414,15 @@ it's larger
 @bottom: 
 
 
+<!-- ##### FUNCTION gtk_window_set_functions_hint ##### -->
+<para>
+
+</para>
+
+@window: 
+@functions: 
+
+
 <!-- ##### FUNCTION gtk_window_set_has_frame ##### -->
 <para>
 
index 9dea2a36a3c565d48648138a0ebe1dc5b75279ee..f00bda8f65d1d7ac5c7d4a83fdbdd9d2391bbd5c 100644 (file)
@@ -1,3 +1,32 @@
+2001-05-04  Havoc Pennington  <hp@redhat.com>
+
+       * pixops/pixops.c (pixops_process): merge fix from stable: Patch
+        from hoshem@mel.comcen.com.au to fix nonzero X offsets.  Fixes
+        bug #50371.
+       
+        * gdk-pixbuf/pixops/pixops.c (pixops_composite_nearest): merge
+       from stable: Patch from OKADA Mitsuru <m-okada@fjb.co.jp> to fix
+       confusion of using "src" instead of "p".
+        (pixops_composite_color_nearest): Use a more accurate (and
+       correct, to begin with) compositing method.  This cures checks
+       showing through on images with no alpha.
+
+       * gdk-pixbuf.c (gdk_pixbuf_fill): fix bug that left some trailing
+       bytes unfilled.
+
+       * gdk-pixbuf-io.h: fix UpdatedNotifyFunc to use signed ints
+
+       * gdk-pixbuf-loader.h (struct _GdkPixbufLoaderClass): Change
+       area_updated signal to use signed ints.  Removed animation-related
+       signals.
+
+       * io-gif.c, io-gif-animation.h, io-gif-animation.c: Massive
+       rewrite action
+
+       * gdk-pixbuf-animation.c: Add GdkPixbufAnimationIter to abstract
+       all the pesky details. Remove old frame-based API. Make
+       GdkPixbufAnimation an abstract base class, derived by the loaders.
+
 Sun Apr 22 15:51:32 2001  Owen Taylor  <otaylor@redhat.com>
 
        * Makefile.am (LDADDS): Add $(MATH_LIB).
index c8ba6e08831b476ed6a6a5d075de8c75ecaaa71e..b006435ccddd1e536978a7fa670d70bcb881c1aa 100644 (file)
@@ -32,8 +32,8 @@ libpixbufloader_xpm_la_LIBADD =
 #
 # The GIF loader
 #
-libpixbufloader_static_gif_la_SOURCES = io-gif.c
-libpixbufloader_gif_la_SOURCES = io-gif.c
+libpixbufloader_static_gif_la_SOURCES = io-gif.c io-gif-animation.c io-gif-animation.h
+libpixbufloader_gif_la_SOURCES = io-gif.c io-gif-animation.c io-gif-animation.h
 libpixbufloader_gif_la_LDFLAGS = -avoid-version -module
 libpixbufloader_gif_la_LIBADD =
 
index cc325590480c4e87538ac9add0de156dce453a74..274813c503c0722e7abb653972732f22ca6328d0 100644 (file)
@@ -1,3 +1,4 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
 /* GdkPixbuf library - Simple animation support
  *
  * Copyright (C) 1999 The Free Software Foundation
 #include "gdk-pixbuf-io.h"
 #include "gdk-pixbuf-private.h"
 
-static void gdk_pixbuf_animation_class_init (GdkPixbufAnimationClass *klass);
-static void gdk_pixbuf_animation_finalize   (GObject        *object);
+typedef struct _GdkPixbufNonAnim GdkPixbufNonAnim;
+typedef struct _GdkPixbufNonAnimClass GdkPixbufNonAnimClass;
+
+#define GDK_TYPE_PIXBUF_NON_ANIM              (gdk_pixbuf_non_anim_get_type ())
+#define GDK_PIXBUF_NON_ANIM(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_PIXBUF_NON_ANIM, GdkPixbufNonAnim))
+#define GDK_IS_PIXBUF_NON_ANIM(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_PIXBUF_NON_ANIM))
+
+#define GDK_PIXBUF_NON_ANIM_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_PIXBUF_NON_ANIM, GdkPixbufNonAnimClass))
+#define GDK_IS_PIXBUF_NON_ANIM_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_PIXBUF_NON_ANIM))
+#define GDK_PIXBUF_NON_ANIM_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_PIXBUF_NON_ANIM, GdkPixbufNonAnimClass))
+
+/* Private part of the GdkPixbufNonAnim structure */
+struct _GdkPixbufNonAnim {
+        GdkPixbufAnimation parent_instance;
+
+        GdkPixbuf *pixbuf;
+};
+
+struct _GdkPixbufNonAnimClass {
+        GdkPixbufAnimationClass parent_class;
+        
+};
+
+static GType gdk_pixbuf_non_anim_get_type (void) G_GNUC_CONST;
 
 \f
 
-static gpointer parent_class;
+typedef struct _GdkPixbufNonAnimIter GdkPixbufNonAnimIter;
+typedef struct _GdkPixbufNonAnimIterClass GdkPixbufNonAnimIterClass;
+
+
+#define GDK_TYPE_PIXBUF_NON_ANIM_ITER              (gdk_pixbuf_non_anim_iter_get_type ())
+#define GDK_PIXBUF_NON_ANIM_ITER(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_PIXBUF_NON_ANIM_ITER, GdkPixbufNonAnimIter))
+#define GDK_IS_PIXBUF_NON_ANIM_ITER(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_PIXBUF_NON_ANIM_ITER))
+
+#define GDK_PIXBUF_NON_ANIM_ITER_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_PIXBUF_NON_ANIM_ITER, GdkPixbufNonAnimIterClass))
+#define GDK_IS_PIXBUF_NON_ANIM_ITER_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_PIXBUF_NON_ANIM_ITER))
+#define GDK_PIXBUF_NON_ANIM_ITER_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_PIXBUF_NON_ANIM_ITER, GdkPixbufNonAnimIterClass))
+
+struct _GdkPixbufNonAnimIter {
+        GdkPixbufAnimationIter parent_instance;
+
+        GdkPixbufNonAnim   *non_anim;
+};
+
+struct _GdkPixbufNonAnimIterClass {
+        GdkPixbufAnimationIterClass parent_class;
+
+};
+
+static GType gdk_pixbuf_non_anim_iter_get_type (void) G_GNUC_CONST;
+
+\f
 
 GType
 gdk_pixbuf_animation_get_type (void)
@@ -43,7 +91,7 @@ gdk_pixbuf_animation_get_type (void)
                         sizeof (GdkPixbufAnimationClass),
                         (GBaseInitFunc) NULL,
                         (GBaseFinalizeFunc) NULL,
-                        (GClassInitFunc) gdk_pixbuf_animation_class_init,
+                        (GClassInitFunc) NULL,
                         NULL,           /* class_finalize */
                         NULL,           /* class_data */
                         sizeof (GdkPixbufAnimation),
@@ -59,35 +107,6 @@ gdk_pixbuf_animation_get_type (void)
         return object_type;
 }
 
-static void
-gdk_pixbuf_animation_class_init (GdkPixbufAnimationClass *klass)
-{
-        GObjectClass *object_class = G_OBJECT_CLASS (klass);
-        
-        parent_class = g_type_class_peek_parent (klass);
-        
-        object_class->finalize = gdk_pixbuf_animation_finalize;
-}
-
-static void
-gdk_pixbuf_animation_finalize (GObject *object)
-{
-        GdkPixbufAnimation *animation = GDK_PIXBUF_ANIMATION (object);
-
-        GList *l;
-        GdkPixbufFrame *frame;
-        
-        for (l = animation->frames; l; l = l->next) {
-                frame = l->data;
-                gdk_pixbuf_unref (frame->pixbuf);
-                g_free (frame);
-        }
-        
-        g_list_free (animation->frames);
-        
-        G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
 \f
 
 /**
@@ -154,7 +173,6 @@ gdk_pixbuf_animation_new_from_file (const char *filename,
 
        if (image_module->load_animation == NULL) {
                GdkPixbuf *pixbuf;
-               GdkPixbufFrame *frame;
 
                /* Keep this logic in sync with gdk_pixbuf_new_from_file() */
 
@@ -191,20 +209,9 @@ gdk_pixbuf_animation_new_from_file (const char *filename,
                if (pixbuf == NULL)
                         return NULL;
 
-               frame = g_new (GdkPixbufFrame, 1);
-               frame->pixbuf = pixbuf;
-                g_object_ref (G_OBJECT (frame->pixbuf));
-               frame->x_offset = 0;
-               frame->y_offset = 0;
-               frame->delay_time = -1;
-               frame->action = GDK_PIXBUF_FRAME_RETAIN;
+                animation = gdk_pixbuf_non_anim_new (pixbuf);
 
-               animation = g_object_new (GDK_TYPE_PIXBUF_ANIMATION, NULL);
-
-               animation->n_frames = 1;
-               animation->frames = g_list_prepend (NULL, frame);
-               animation->width = gdk_pixbuf_get_width (pixbuf);
-               animation->height = gdk_pixbuf_get_height (pixbuf);
+                g_object_unref (G_OBJECT (pixbuf));
        } else {
                fseek (f, 0, SEEK_SET);
                animation = (* image_module->load_animation) (f, error);
@@ -261,6 +268,46 @@ gdk_pixbuf_animation_unref (GdkPixbufAnimation *animation)
         g_object_unref (G_OBJECT (animation));
 }
 
+/**
+ * gdk_pixbuf_animation_is_static_image:
+ * @animation: a #GdkPixbufAnimation
+ * 
+ * If you load a file with gdk_pixbuf_animation_new_from_file() and it turns
+ * out to be a plain, unanimated image, then this function will return
+ * %TRUE. Use gdk_pixbuf_animation_get_static_image() to retrieve
+ * the image.
+ * 
+ * Return value: %TRUE if the "animation" was really just an image
+ **/
+gboolean
+gdk_pixbuf_animation_is_static_image (GdkPixbufAnimation *animation)
+{
+       g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION (animation), FALSE);
+
+        return GDK_PIXBUF_ANIMATION_GET_CLASS (animation)->is_static_image (animation);
+}
+
+/**
+ * gdk_pixbuf_animation_get_static_image:
+ * @animation: a #GdkPixbufAnimation
+ * 
+ * If an animation is really just a plain image (has only one frame),
+ * this function returns that image. If the animation is an animation,
+ * this function returns a reasonable thing to display as a static
+ * unanimated image, which might be the first frame, or something more
+ * sophisticated. If an animation hasn't loaded any frames yet, this
+ * function will return %NULL.
+ * 
+ * Return value: unanimated image representing the animation
+ **/
+GdkPixbuf*
+gdk_pixbuf_animation_get_static_image (GdkPixbufAnimation *animation)
+{
+       g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION (animation), NULL);
+        
+        return GDK_PIXBUF_ANIMATION_GET_CLASS (animation)->get_static_image (animation);
+}
+
 /**
  * gdk_pixbuf_animation_get_width:
  * @animation: An animation.
@@ -272,9 +319,16 @@ gdk_pixbuf_animation_unref (GdkPixbufAnimation *animation)
 int
 gdk_pixbuf_animation_get_width (GdkPixbufAnimation *animation)
 {
-       g_return_val_if_fail (animation != NULL, -1);
+        int width;
+        
+       g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION (animation), 0);
+
+        width = 0;
+        GDK_PIXBUF_ANIMATION_GET_CLASS (animation)->get_size (animation,
+                                                              &width, NULL);
+        
 
-       return animation->width;
+       return width;
 }
 
 /**
@@ -288,179 +342,444 @@ gdk_pixbuf_animation_get_width (GdkPixbufAnimation *animation)
 int
 gdk_pixbuf_animation_get_height (GdkPixbufAnimation *animation)
 {
-       g_return_val_if_fail (animation != NULL, -1);
-
-       return animation->height;
-}
+        int height;
+        
+       g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION (animation), 0);
 
-/**
- * gdk_pixbuf_animation_get_num_frames:
- * @animation: An animation.
- *
- * Queries the number of frames in a pixbuf animation.
- * 
- * Return value: Number of frames in the animation.
- **/
-int
-gdk_pixbuf_animation_get_num_frames (GdkPixbufAnimation *animation)
-{
-       g_return_val_if_fail (animation != NULL, -1);
+        height = 0;
+        GDK_PIXBUF_ANIMATION_GET_CLASS (animation)->get_size (animation,
+                                                              NULL, &height);
+        
 
-       return animation->n_frames;
+       return height;
 }
 
+
 /**
- * gdk_pixbuf_animation_get_frames:
- * @animation: An animation.
+ * gdk_pixbuf_animation_get_iter:
+ * @animation: a #GdkPixbufAnimation
+ * @start_time: time when the animation starts playing
+ * 
+ * Get an iterator for displaying an animation. The iterator provides
+ * the frames that should be displayed at a given time.
+ * It should be freed after use with g_object_unref().
+ * 
+ * @start_time would normally come from g_get_current_time(), and
+ * marks the beginning of animation playback. After creating an
+ * iterator, you should immediately display the pixbuf returned by
+ * gdk_pixbuf_animation_iter_get_pixbuf(). Then, you should install a
+ * timeout (with g_timeout_add()) or by some other mechanism ensure
+ * that you'll update the image after
+ * gdk_pixbuf_animation_iter_get_delay_time() milliseconds. Each time
+ * the image is updated, you should reinstall the timeout with the new,
+ * possibly-changed delay time.
+ *
+ * As a shortcut, if @start_time is %NULL, the result of
+ * g_get_current_time() will be used automatically.
  *
- * Queries the list of frames of an animation.
+ * To update the image (i.e. possibly change the result of
+ * gdk_pixbuf_animation_iter_get_pixbuf() to a new frame of the animation),
+ * call gdk_pixbuf_animation_iter_advance().
+ *
+ * If you're using #GdkPixbufLoader, in addition to updating the image
+ * after the delay time, you should also update it whenever you
+ * receive the area_updated signal and
+ * gdk_pixbuf_animation_iter_on_currently_loading_frame() returns
+ * %TRUE. In this case, the frame currently being fed into the loader
+ * has received new data, so needs to be refreshed. The delay time for
+ * a frame may also be modified after an area_updated signal, for
+ * example if the delay time for a frame is encoded in the data after
+ * the frame itself. So your timeout should be reinstalled after any
+ * area_updated signal.
+ *
+ * A delay time of -1 is possible, indicating "infinite."
  * 
- * Return value: List of frames in the animation; this is a #GList of
- * #GdkPixbufFrame structures.
+ * Return value: an iterator to move over the animation
  **/
-GList *
-gdk_pixbuf_animation_get_frames (GdkPixbufAnimation *animation)
+GdkPixbufAnimationIter*
+gdk_pixbuf_animation_get_iter (GdkPixbufAnimation *animation,
+                               const GTimeVal     *start_time)
 {
-       g_return_val_if_fail (animation != NULL, NULL);
+        GTimeVal val;
+        
+        g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION (animation), NULL);
+
 
-       return animation->frames;
+        if (start_time)
+                val = *start_time;
+        else
+                g_get_current_time (&val);
+        
+        return GDK_PIXBUF_ANIMATION_GET_CLASS (animation)->get_iter (animation, &val);
 }
 
 \f
 
-/**
- * gdk_pixbuf_frame_get_pixbuf:
- * @frame: A pixbuf animation frame.
- * 
- * Queries the pixbuf of an animation frame.
- * 
- * Return value: A pixbuf.
- **/
-GdkPixbuf *
-gdk_pixbuf_frame_get_pixbuf (GdkPixbufFrame *frame)
+GType
+gdk_pixbuf_animation_iter_get_type (void)
 {
-       g_return_val_if_fail (frame != NULL, NULL);
+        static GType object_type = 0;
 
-       return frame->pixbuf;
+        if (!object_type) {
+                static const GTypeInfo object_info = {
+                        sizeof (GdkPixbufAnimationIterClass),
+                        (GBaseInitFunc) NULL,
+                        (GBaseFinalizeFunc) NULL,
+                        (GClassInitFunc) NULL,
+                        NULL,           /* class_finalize */
+                        NULL,           /* class_data */
+                        sizeof (GdkPixbufAnimationIter),
+                        0,              /* n_preallocs */
+                        (GInstanceInitFunc) NULL,
+                };
+                
+                object_type = g_type_register_static (G_TYPE_OBJECT,
+                                                      "GdkPixbufAnimationIter",
+                                                      &object_info, 0);
+        }
+  
+        return object_type;
 }
 
 /**
- * gdk_pixbuf_frame_get_x_offset:
- * @frame: A pixbuf animation frame.
+ * gdk_pixbuf_animation_iter_get_delay_time:
+ * @iter: an animation iterator
  * 
- * Queries the X offset of an animation frame.
- * 
- * Return value: X offset from the top left corner of the animation.
+ * Gets the number of milliseconds the current pixbuf should be displayed,
+ * or -1 if the current pixbuf should be displayed forever. g_timeout_add()
+ * conveniently takes a timeout in milliseconds, so you can use a timeout
+ * to schedule the next update.
+ *
+ * Return value: delay time in milliseconds (thousandths of a second)
  **/
 int
-gdk_pixbuf_frame_get_x_offset (GdkPixbufFrame *frame)
+gdk_pixbuf_animation_iter_get_delay_time (GdkPixbufAnimationIter *iter)
 {
-       g_return_val_if_fail (frame != NULL, -1);
-
-       return frame->x_offset;
+        g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION_ITER (iter), -1);
+  
+        return GDK_PIXBUF_ANIMATION_ITER_GET_CLASS (iter)->get_delay_time (iter);
 }
 
 /**
- * gdk_pixbuf_frame_get_y_offset:
- * @frame: A pixbuf animation frame.
+ * gdk_pixbuf_animation_iter_get_pixbuf:
+ * @iter: an animation iterator
  * 
- * Queries the Y offset of an animation frame.
- * 
- * Return value: Y offset from the top left corner of the animation.
+ * Gets the current pixbuf which should be displayed; the pixbuf will
+ * be the same size as the animation itself
+ * (gdk_pixbuf_animation_get_width(),
+ * gdk_pixbuf_animation_get_height()). This pixbuf should be displayed
+ * for gdk_pixbuf_animation_get_delay_time() milliseconds.  The caller
+ * of this function does not own a reference to the returned pixbuf;
+ * the returned pixbuf will become invalid when the iterator advances
+ * to the next frame, which may happen anytime you call
+ * gdk_pixbuf_animation_iter_advance(). Copy the pixbuf to keep it
+ * (don't just add a reference), as it may get recycled as you advance
+ * the iterator.
+ *
+ * Return value: the pixbuf to be displayed
  **/
-int
-gdk_pixbuf_frame_get_y_offset (GdkPixbufFrame *frame)
+GdkPixbuf*
+gdk_pixbuf_animation_iter_get_pixbuf (GdkPixbufAnimationIter *iter)
 {
-       g_return_val_if_fail (frame != NULL, -1);
-
-       return frame->y_offset;
+        g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION_ITER (iter), NULL);
+  
+        return GDK_PIXBUF_ANIMATION_ITER_GET_CLASS (iter)->get_pixbuf (iter);
 }
 
 /**
- * gdk_pixbuf_frame_get_delay_time:
- * @frame: A pixbuf animation frame.
- * 
- * Queries the delay time in milliseconds of an animation frame.
+ * gdk_pixbuf_animation_iter_on_currently_loading_frame:
+ * @iter: a #GdkPixbufAnimationIter
+ *
+ * Used to determine how to respond to the area_updated signal on
+ * #GdkPixbufLoader when loading an animation. area_updated is emitted
+ * for an area of the frame currently streaming in to the loader. So if
+ * you're on the currently loading frame, you need to redraw the screen for
+ * the updated area.
  * 
- * Return value: Delay time in milliseconds.
+ * Return value: %TRUE if the frame we're on is partially loaded, or the last frame
  **/
-int
-gdk_pixbuf_frame_get_delay_time (GdkPixbufFrame *frame)
+gboolean
+gdk_pixbuf_animation_iter_on_currently_loading_frame (GdkPixbufAnimationIter *iter)
 {
-       g_return_val_if_fail (frame != NULL, -1);
-
-       return frame->delay_time;
+        g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION_ITER (iter), FALSE);
+        
+        return GDK_PIXBUF_ANIMATION_ITER_GET_CLASS (iter)->on_currently_loading_frame (iter);
 }
 
 /**
- * gdk_pixbuf_frame_get_action:
- * @frame: A pixbuf animation frame.
+ * gdk_pixbuf_animation_iter_advance:
+ * @iter: a #GdkPixbufAnimationIter
+ * @current_time: current time
+ *
+ * Possibly advances an animation to a new frame. Chooses the frame based
+ * on the start time passed to gdk_pixbuf_animation_get_iter().
  * 
- * Queries the overlay action of an animation frame.
+ * @current_time would normally come from g_get_current_time(), and
+ * must be greater than or equal to the time passed to
+ * gdk_pixbuf_animation_get_iter(), and must increase or remain
+ * unchanged each time gdk_pixbuf_animation_iter_get_pixbuf() is
+ * called. That is, you can't go backward in time; animations only
+ * play forward.
+ *
+ * As a shortcut, pass %NULL for the current time and g_get_current_time()
+ * will be invoked on your behalf. So you only need to explicitly pass
+ * @current_time if you're doing something odd like playing the animation
+ * at double speed.
+ *
+ * If this function returns %FALSE, there's no need to update the animation
+ * display, assuming the display had been rendered prior to advancing;
+ * if %TRUE, you need to call gdk_animation_iter_get_pixbuf() and update the
+ * display with the new pixbuf.
+ *
+ * Returns: %TRUE if the image may need updating
  * 
- * Return value: Overlay action for this frame.
  **/
-GdkPixbufFrameAction
-gdk_pixbuf_frame_get_action (GdkPixbufFrame *frame)
+gboolean
+gdk_pixbuf_animation_iter_advance (GdkPixbufAnimationIter *iter,
+                                   const GTimeVal         *current_time)
 {
-       g_return_val_if_fail (frame != NULL, GDK_PIXBUF_FRAME_RETAIN);
+        GTimeVal val;
+        
+        g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION_ITER (iter), FALSE);
 
-       return frame->action;
+        if (current_time)
+                val = *current_time;
+        else
+                g_get_current_time (&val);
+        
+        return GDK_PIXBUF_ANIMATION_ITER_GET_CLASS (iter)->advance (iter, &val);
 }
 
-/**
- * gdk_pixbuf_frame_copy:
- * @src: a #GdkPixbufFrame to copy
- * 
- * Copies a #GdkPixbufFrame. Free the result
- * with gdk_pixbuf_frame_free().
- * 
- * Return value: a new #GdkPixbufFrame
- **/
-GdkPixbufFrame*
-gdk_pixbuf_frame_copy (GdkPixbufFrame *src)
+\f
+
+static void gdk_pixbuf_non_anim_class_init (GdkPixbufNonAnimClass *klass);
+static void gdk_pixbuf_non_anim_finalize   (GObject        *object);
+
+static gboolean                gdk_pixbuf_non_anim_is_static_image  (GdkPixbufAnimation *animation);
+static GdkPixbuf*              gdk_pixbuf_non_anim_get_static_image (GdkPixbufAnimation *animation);
+static void                    gdk_pixbuf_non_anim_get_size         (GdkPixbufAnimation *anim,
+                                                                     int                *width,
+                                                                     int                *height);
+static GdkPixbufAnimationIter* gdk_pixbuf_non_anim_get_iter         (GdkPixbufAnimation *anim,
+                                                                     const GTimeVal     *start_time);
+
+
+
+\f
+
+static gpointer non_parent_class;
+
+GType
+gdk_pixbuf_non_anim_get_type (void)
 {
-  GdkPixbufFrame *frame;
-
-  frame = g_new (GdkPixbufFrame, 1);
-  frame->pixbuf = src->pixbuf;
-  g_object_ref (G_OBJECT (frame->pixbuf));
-  frame->x_offset = src->x_offset;
-  frame->y_offset = src->y_offset;
-  frame->delay_time = src->delay_time;
-  frame->action = src->action;
-  
-  return frame;
+        static GType object_type = 0;
+
+        if (!object_type) {
+                static const GTypeInfo object_info = {
+                        sizeof (GdkPixbufNonAnimClass),
+                        (GBaseInitFunc) NULL,
+                        (GBaseFinalizeFunc) NULL,
+                        (GClassInitFunc) gdk_pixbuf_non_anim_class_init,
+                        NULL,           /* class_finalize */
+                        NULL,           /* class_data */
+                        sizeof (GdkPixbufNonAnim),
+                        0,              /* n_preallocs */
+                        (GInstanceInitFunc) NULL,
+                };
+                
+                object_type = g_type_register_static (GDK_TYPE_PIXBUF_ANIMATION,
+                                                      "GdkPixbufNonAnim",
+                                                      &object_info, 0);
+        }
+        
+        return object_type;
 }
 
-/**
- * gdk_pixbuf_frame_free:
- * @frame: a #GdkPixbufFrame
- * 
- * Frees a #GdkPixbufFrame. Don't do this with frames you got from
- * #GdkPixbufAnimation, usually the animation owns those (it doesn't
- * make a copy before returning the frame).
- **/
-void
-gdk_pixbuf_frame_free (GdkPixbufFrame *frame)
+static void
+gdk_pixbuf_non_anim_class_init (GdkPixbufNonAnimClass *klass)
 {
-  g_return_if_fail (frame != NULL);
+        GObjectClass *object_class = G_OBJECT_CLASS (klass);
+        GdkPixbufAnimationClass *anim_class = GDK_PIXBUF_ANIMATION_CLASS (klass);
+        
+        non_parent_class = g_type_class_peek_parent (klass);
+        
+        object_class->finalize = gdk_pixbuf_non_anim_finalize;
+
+        anim_class->is_static_image = gdk_pixbuf_non_anim_is_static_image;
+        anim_class->get_static_image = gdk_pixbuf_non_anim_get_static_image;
+        anim_class->get_size = gdk_pixbuf_non_anim_get_size;
+        anim_class->get_iter = gdk_pixbuf_non_anim_get_iter;
+}
+
+static void
+gdk_pixbuf_non_anim_finalize (GObject *object)
+{
+        GdkPixbufNonAnim *non_anim = GDK_PIXBUF_NON_ANIM (object);
+
+        if (non_anim->pixbuf)
+                g_object_unref (G_OBJECT (non_anim->pixbuf));
+        
+        G_OBJECT_CLASS (non_parent_class)->finalize (object);
+}
+
+GdkPixbufAnimation*
+gdk_pixbuf_non_anim_new (GdkPixbuf *pixbuf)
+{
+        GdkPixbufNonAnim *non_anim;
+
+        non_anim = g_object_new (GDK_TYPE_PIXBUF_NON_ANIM, NULL);
+
+        non_anim->pixbuf = pixbuf;
+
+        if (pixbuf)
+                g_object_ref (G_OBJECT (pixbuf));
 
-  g_object_unref (G_OBJECT (frame->pixbuf));
-  g_free (frame);
+        return GDK_PIXBUF_ANIMATION (non_anim);
 }
 
+static gboolean
+gdk_pixbuf_non_anim_is_static_image  (GdkPixbufAnimation *animation)
+{
+
+        return TRUE;
+}
+
+static GdkPixbuf*
+gdk_pixbuf_non_anim_get_static_image (GdkPixbufAnimation *animation)
+{
+        GdkPixbufNonAnim *non_anim;
+
+        non_anim = GDK_PIXBUF_NON_ANIM (animation);
+
+        return non_anim->pixbuf;
+}
+
+static void
+gdk_pixbuf_non_anim_get_size (GdkPixbufAnimation *anim,
+                              int                *width,
+                              int                *height)
+{
+        GdkPixbufNonAnim *non_anim;
+
+        non_anim = GDK_PIXBUF_NON_ANIM (anim);
+
+        if (width)
+                *width = gdk_pixbuf_get_width (non_anim->pixbuf);
+
+        if (height)
+                *height = gdk_pixbuf_get_height (non_anim->pixbuf);
+}
+
+
+static GdkPixbufAnimationIter*
+gdk_pixbuf_non_anim_get_iter (GdkPixbufAnimation *anim,
+                              const GTimeVal     *start_time)
+{
+        GdkPixbufNonAnimIter *iter;
+
+        iter = g_object_new (GDK_TYPE_PIXBUF_NON_ANIM_ITER, NULL);
+
+        iter->non_anim = GDK_PIXBUF_NON_ANIM (anim);
+
+        g_object_ref (G_OBJECT (iter->non_anim));
+        
+        return GDK_PIXBUF_ANIMATION_ITER (iter);
+}
+
+\f
+
+static void gdk_pixbuf_non_anim_iter_class_init (GdkPixbufNonAnimIterClass *klass);
+static void gdk_pixbuf_non_anim_iter_finalize   (GObject                   *object);
+static int        gdk_pixbuf_non_anim_iter_get_delay_time             (GdkPixbufAnimationIter *iter);
+static GdkPixbuf* gdk_pixbuf_non_anim_iter_get_pixbuf                 (GdkPixbufAnimationIter *iter);
+static gboolean   gdk_pixbuf_non_anim_iter_on_currently_loading_frame (GdkPixbufAnimationIter *iter);
+static gboolean   gdk_pixbuf_non_anim_iter_advance                    (GdkPixbufAnimationIter *iter,
+                                                                       const GTimeVal         *current_time);
+
+
+
+\f
+
+static gpointer non_iter_parent_class;
+
 GType
-gdk_pixbuf_frame_get_type (void)
+gdk_pixbuf_non_anim_iter_get_type (void)
+{
+        static GType object_type = 0;
+
+        if (!object_type) {
+                static const GTypeInfo object_info = {
+                        sizeof (GdkPixbufNonAnimIterClass),
+                        (GBaseInitFunc) NULL,
+                        (GBaseFinalizeFunc) NULL,
+                        (GClassInitFunc) gdk_pixbuf_non_anim_iter_class_init,
+                        NULL,           /* class_finalize */
+                        NULL,           /* class_data */
+                        sizeof (GdkPixbufNonAnimIter),
+                        0,              /* n_preallocs */
+                        (GInstanceInitFunc) NULL,
+                };
+                
+                object_type = g_type_register_static (GDK_TYPE_PIXBUF_ANIMATION_ITER,
+                                                      "GdkPixbufNonAnimIter",
+                                                      &object_info, 0);
+        }
+        
+        return object_type;
+}
+
+static void
+gdk_pixbuf_non_anim_iter_class_init (GdkPixbufNonAnimIterClass *klass)
+{
+        GObjectClass *object_class = G_OBJECT_CLASS (klass);
+        GdkPixbufAnimationIterClass *anim_iter_class =
+                GDK_PIXBUF_ANIMATION_ITER_CLASS (klass);
+        
+        non_iter_parent_class = g_type_class_peek_parent (klass);
+        
+        object_class->finalize = gdk_pixbuf_non_anim_iter_finalize;
+
+        anim_iter_class->get_delay_time = gdk_pixbuf_non_anim_iter_get_delay_time;
+        anim_iter_class->get_pixbuf = gdk_pixbuf_non_anim_iter_get_pixbuf;
+        anim_iter_class->on_currently_loading_frame = gdk_pixbuf_non_anim_iter_on_currently_loading_frame;
+        anim_iter_class->advance = gdk_pixbuf_non_anim_iter_advance;
+}
+
+static void
+gdk_pixbuf_non_anim_iter_finalize (GObject *object)
 {
-  static GType our_type = 0;
+        GdkPixbufNonAnimIter *iter = GDK_PIXBUF_NON_ANIM_ITER (object);
 
-  if (our_type == 0)
-    our_type = g_boxed_type_register_static ("GdkPixbufFrame",
-                                            NULL,
-                                            gdk_pixbuf_frame_copy,
-                                            gdk_pixbuf_frame_free,
-                                            FALSE);
+        g_object_unref (G_OBJECT (iter->non_anim));
+        
+        G_OBJECT_CLASS (non_iter_parent_class)->finalize (object);
+}
+
+static int
+gdk_pixbuf_non_anim_iter_get_delay_time (GdkPixbufAnimationIter *iter)
+{
+        return -1; /* show only frame forever */
+}
 
-  return our_type;
+static GdkPixbuf*
+gdk_pixbuf_non_anim_iter_get_pixbuf (GdkPixbufAnimationIter *iter)
+{
+        return GDK_PIXBUF_NON_ANIM_ITER (iter)->non_anim->pixbuf;
 }
+
+
+static gboolean
+gdk_pixbuf_non_anim_iter_on_currently_loading_frame (GdkPixbufAnimationIter *iter)
+{
+        return TRUE;
+}
+        
+static gboolean
+gdk_pixbuf_non_anim_iter_advance (GdkPixbufAnimationIter *iter,
+                                  const GTimeVal         *current_time)
+{
+
+        /* Advancing never requires a refresh */
+        return FALSE;
+}
+
index d4cf389fddd1ab67a3e81d5daf2587a34c38e0ce..b66bcaf08b0ef24d0b32a4d1e85d3acda107eacb 100644 (file)
@@ -39,16 +39,15 @@ extern "C" {
 
 \f
 
-typedef void (* ModulePreparedNotifyFunc) (GdkPixbuf *pixbuf, gpointer user_data);
-typedef void (* ModuleUpdatedNotifyFunc) (GdkPixbuf *pixbuf,
-                                         guint x, guint y,
-                                         guint width, guint height,
-                                         gpointer user_data);
-/* Needed only for animated images. */
-typedef void (* ModuleFrameDoneNotifyFunc) (GdkPixbufFrame *frame,
-                                           gpointer user_data);
-typedef void (* ModuleAnimationDoneNotifyFunc) (GdkPixbuf *pixbuf,
-                                               gpointer user_data);
+typedef void (* ModulePreparedNotifyFunc) (GdkPixbuf          *pixbuf,
+                                           GdkPixbufAnimation *anim,
+                                           gpointer            user_data);
+typedef void (* ModuleUpdatedNotifyFunc)  (GdkPixbuf *pixbuf,
+                                           int        x,
+                                           int        y,
+                                           int        width,
+                                           int        height,
+                                           gpointer   user_data);
 
 typedef struct _GdkPixbufModule GdkPixbufModule;
 struct _GdkPixbufModule {
@@ -63,8 +62,6 @@ struct _GdkPixbufModule {
 
         gpointer (* begin_load)     (ModulePreparedNotifyFunc prepare_func,
                                      ModuleUpdatedNotifyFunc update_func,
-                                     ModuleFrameDoneNotifyFunc frame_done_func,
-                                     ModuleAnimationDoneNotifyFunc anim_done_func,
                                      gpointer user_data,
                                      GError **error);
         gboolean (* stop_load)      (gpointer context,
index 2a8d2658e492f7964bc2e661815aceac4d4a0438..a9148d7fd574353fcc1fc5683d73a7176108fa5f 100644 (file)
@@ -35,8 +35,6 @@
 enum {
   AREA_UPDATED,
   AREA_PREPARED,
-  FRAME_DONE,
-  ANIMATION_DONE,
   CLOSED,
   LAST_SIGNAL
 };
@@ -56,7 +54,6 @@ static guint    pixbuf_loader_signals[LAST_SIGNAL] = { 0 };
 
 typedef struct
 {
-  GdkPixbuf *pixbuf;
   GdkPixbufAnimation *animation;
   gboolean closed;
   guchar header_buf[LOADER_HEADER_SIZE];
@@ -136,25 +133,6 @@ gdk_pixbuf_loader_class_init (GdkPixbufLoaderClass *class)
                    G_TYPE_INT,
                    G_TYPE_INT);
   
-  pixbuf_loader_signals[FRAME_DONE] =
-    g_signal_newc ("frame_done",
-                   G_TYPE_FROM_CLASS (object_class),
-                   G_SIGNAL_RUN_LAST,
-                   G_STRUCT_OFFSET (GdkPixbufLoaderClass, frame_done),
-                  NULL, NULL,
-                   gdk_pixbuf_marshal_VOID__POINTER,
-                   G_TYPE_NONE, 1,
-                   GDK_TYPE_PIXBUF_FRAME);
-  
-  pixbuf_loader_signals[ANIMATION_DONE] =
-    g_signal_newc ("animation_done",
-                   G_TYPE_FROM_CLASS (object_class),
-                   G_SIGNAL_RUN_LAST,                   
-                   G_STRUCT_OFFSET (GdkPixbufLoaderClass, animation_done),
-                  NULL, NULL,
-                   gdk_pixbuf_marshal_VOID__VOID,
-                   G_TYPE_NONE, 0);
-  
   pixbuf_loader_signals[CLOSED] =
     g_signal_newc ("closed",
                    G_TYPE_FROM_CLASS (object_class),
@@ -188,9 +166,6 @@ gdk_pixbuf_loader_finalize (GObject *object)
   
   if (priv->animation)
     gdk_pixbuf_animation_unref (priv->animation);
-
-  if (priv->pixbuf)
-    gdk_pixbuf_unref (priv->pixbuf);
   
   g_free (priv);
   
@@ -198,26 +173,30 @@ gdk_pixbuf_loader_finalize (GObject *object)
 }
 
 static void
-gdk_pixbuf_loader_prepare (GdkPixbuf *pixbuf,
-                          gpointer   loader)
+gdk_pixbuf_loader_prepare (GdkPixbuf          *pixbuf,
+                           GdkPixbufAnimation *anim,
+                          gpointer            loader)
 {
   GdkPixbufLoaderPrivate *priv = NULL;
   
   priv = GDK_PIXBUF_LOADER (loader)->priv;
-  gdk_pixbuf_ref (pixbuf);
 
-  g_assert (priv->pixbuf == NULL);
+  if (anim)
+    g_object_ref (G_OBJECT (anim));
+  else
+    anim = gdk_pixbuf_non_anim_new (pixbuf);
+  
+  priv->animation = anim;
   
-  priv->pixbuf = pixbuf;
   g_signal_emit (G_OBJECT (loader), pixbuf_loader_signals[AREA_PREPARED], 0);
 }
 
 static void
 gdk_pixbuf_loader_update (GdkPixbuf *pixbuf,
-                         guint      x,
-                         guint      y,
-                         guint      width,
-                         guint      height,
+                         gint       x,
+                         gint       y,
+                         gint       width,
+                         gint       height,
                          gpointer   loader)
 {
   GdkPixbufLoaderPrivate *priv = NULL;
@@ -229,82 +208,8 @@ gdk_pixbuf_loader_update (GdkPixbuf *pixbuf,
                  0,
                  x, y,
                  /* sanity check in here.  Defend against an errant loader */
-                 MIN (width, gdk_pixbuf_get_width (priv->pixbuf)),
-                 MIN (height, gdk_pixbuf_get_height (priv->pixbuf)));
-}
-
-static void
-gdk_pixbuf_loader_frame_done (GdkPixbufFrame *frame,
-                             gpointer        loader)
-{
-  GdkPixbufLoaderPrivate *priv = NULL;
-  
-  priv = GDK_PIXBUF_LOADER (loader)->priv;
-  
-  priv->pixbuf = NULL;
-  
-  if (priv->animation == NULL)
-    {
-      priv->animation = g_object_new (GDK_TYPE_PIXBUF_ANIMATION, NULL);
-      
-      priv->animation->n_frames = 0;
-      priv->animation->width  = gdk_pixbuf_get_width  (frame->pixbuf) + frame->x_offset;
-      priv->animation->height = gdk_pixbuf_get_height (frame->pixbuf) + frame->y_offset;
-    }
-  else
-    {
-      int w, h;
-      
-      /* update bbox size */
-      w = gdk_pixbuf_get_width (frame->pixbuf) + frame->x_offset;
-      h = gdk_pixbuf_get_height (frame->pixbuf) + frame->y_offset;
-      
-      if (w > priv->animation->width) {
-       priv->animation->width = w;
-      }
-      if (h > priv->animation->height) {
-       priv->animation->height = h;
-      }
-    }
-  
-  priv->animation->frames = g_list_append (priv->animation->frames, frame);
-  priv->animation->n_frames++;
-  g_signal_emit (G_OBJECT (loader),
-                 pixbuf_loader_signals[FRAME_DONE],
-                 0,
-                 frame);
-}
-
-static void
-gdk_pixbuf_loader_animation_done (GdkPixbuf *pixbuf,
-                                 gpointer   loader)
-{
-  GdkPixbufLoaderPrivate *priv = NULL;
-  GdkPixbufFrame    *frame;
-  GList *current = NULL;
-  gint h, w;
-  
-  priv = GDK_PIXBUF_LOADER (loader)->priv;
-  priv->pixbuf = NULL;
-  
-  current = gdk_pixbuf_animation_get_frames (priv->animation);
-  
-  while (current)
-    {
-      frame = (GdkPixbufFrame *) current->data;
-      
-      /* update bbox size */
-      w = gdk_pixbuf_get_width (frame->pixbuf) + frame->x_offset;
-      h = gdk_pixbuf_get_height (frame->pixbuf) + frame->y_offset;
-      
-      if (w > priv->animation->width)
-       priv->animation->width = w;
-      if (h > priv->animation->height)
-       priv->animation->height = h;
-      current = current->next;
-    }
-  
-  g_signal_emit (G_OBJECT (loader), pixbuf_loader_signals[ANIMATION_DONE], 0);
+                 MIN (width, gdk_pixbuf_animation_get_width (priv->animation)),
+                 MIN (height, gdk_pixbuf_animation_get_height (priv->animation)));
 }
 
 static gint
@@ -353,8 +258,6 @@ gdk_pixbuf_loader_load_module (GdkPixbufLoader *loader,
   
   priv->context = priv->image_module->begin_load (gdk_pixbuf_loader_prepare,
                                                  gdk_pixbuf_loader_update,
-                                                 gdk_pixbuf_loader_frame_done,
-                                                 gdk_pixbuf_loader_animation_done,
                                                  loader,
                                                   error);
   
@@ -450,7 +353,7 @@ gdk_pixbuf_loader_write (GdkPixbufLoader *loader,
     {
       gint eaten;
       
-      eaten = gdk_pixbuf_loader_eat_header_write(loader, buf, count, error);
+      eaten = gdk_pixbuf_loader_eat_header_write (loader, buf, count, error);
       if (eaten <= 0)
        return FALSE;
       
@@ -540,13 +443,14 @@ gdk_pixbuf_loader_new_with_type (const char *image_type,
  * "area_prepared" signal has been emitted by the loader; this means
  * that enough data has been read to know the size of the image that
  * will be allocated.  If the loader has not received enough data via
- * gdk_pixbuf_loader_write(), then this function returns NULL.  The
+ * gdk_pixbuf_loader_write(), then this function returns %NULL.  The
  * returned pixbuf will be the same in all future calls to the loader,
  * so simply calling gdk_pixbuf_ref() should be sufficient to continue
  * using it.  Additionally, if the loader is an animation, it will
- * return the first frame of the animation.
+ * return the "static image" of the animation
+ * (see gdk_pixbuf_animation_get_static_image()).
  * 
- * Return value: The GdkPixbuf that the loader is creating, or NULL if not
+ * Return value: The #GdkPixbuf that the loader is creating, or %NULL if not
  * enough data has been read to determine how to create the image buffer.
  **/
 GdkPixbuf *
@@ -560,19 +464,9 @@ gdk_pixbuf_loader_get_pixbuf (GdkPixbufLoader *loader)
   priv = loader->priv;
 
   if (priv->animation)
-    {
-      GList *list;
-      
-      list = gdk_pixbuf_animation_get_frames (priv->animation);
-      if (list != NULL)
-        {
-          GdkPixbufFrame *frame = list->data;
-          
-          return gdk_pixbuf_frame_get_pixbuf (frame);
-        }
-    }
-  
-  return priv->pixbuf;
+    return gdk_pixbuf_animation_get_static_image (priv->animation);
+  else
+    return NULL;
 }
 
 /**
@@ -581,8 +475,9 @@ gdk_pixbuf_loader_get_pixbuf (GdkPixbufLoader *loader)
  *
  * Queries the GdkPixbufAnimation that a pixbuf loader is currently creating.
  * In general it only makes sense to call this function afer the "area_prepared"
- * signal has been emitted by the loader.  If the image is not an animation,
- * then it will return NULL.
+ * signal has been emitted by the loader. If the loader doesn't have enough
+ * bytes yet (hasn't emitted the area_prepared signal) this function will return
+ * %NULL.
  *
  * Return value: The GdkPixbufAnimation that the loader is loading, or NULL if
  not enough data has been read to determine the information.
index 9c47478a22cfd25b8a0b91efa8cac9c2dc773ac7..eea72f30d8428b268d57918333ab1a3049f10b22 100644 (file)
@@ -51,21 +51,21 @@ typedef struct _GdkPixbufLoaderClass GdkPixbufLoaderClass;
 struct _GdkPixbufLoaderClass
 {
   GObjectClass parent_class;
-  
-  void (*area_prepared)   (GdkPixbufLoader *loader);
-  void (*area_updated)    (GdkPixbufLoader *loader,
-                          guint            x,
-                          guint            y,
-                          guint            width,
-                          guint            height);
-  void (*frame_done)      (GdkPixbufLoader *loader,
-                          GdkPixbufFrame  *frame);
-  void (*animation_done)  (GdkPixbufLoader *loader);
-  void (*closed)          (GdkPixbufLoader *loader);
+
+  void (*area_prepared)      (GdkPixbufLoader *loader);
+
+  /* Last known frame needs a redraw for x, y, width, height */
+  void (*area_updated)       (GdkPixbufLoader *loader,
+                              int              x,
+                              int              y,
+                             int              width,
+                             int              height);
+
+  void (*closed)             (GdkPixbufLoader *loader);
 };
 
 
-GType              gdk_pixbuf_loader_get_type      (void) G_GNUC_CONST;
+GType                gdk_pixbuf_loader_get_type      (void) G_GNUC_CONST;
 GdkPixbufLoader *    gdk_pixbuf_loader_new           (void);
 GdkPixbufLoader *    gdk_pixbuf_loader_new_with_type (const char *image_type,
                                                       GError    **error);
index e8eb7248a46f6ee75eaf87beab236d0dd5c5c9e3..0bdae8715de330279c7ae494a69b996b4bd2c57a 100644 (file)
@@ -1,3 +1,4 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
 /* GdkPixbuf library - Private declarations
  *
  * Copyright (C) 1999 The Free Software Foundation
@@ -73,22 +74,6 @@ struct _GdkPixbufClass {
 
 };
 
-/* Private part of the GdkPixbufFrame structure */
-struct _GdkPixbufFrame {
-       /* The pixbuf with this frame's image data */
-       GdkPixbuf *pixbuf;
-
-       /* Offsets for overlaying onto the animation's area */
-       int x_offset;
-       int y_offset;
-
-       /* Frame duration in ms */
-       int delay_time;
-
-       /* Overlay mode */
-       GdkPixbufFrameAction action;
-};
-
 typedef struct _GdkPixbufAnimationClass GdkPixbufAnimationClass;
 
 #define GDK_PIXBUF_ANIMATION_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_PIXBUF_ANIMATION, GdkPixbufAnimationClass))
@@ -99,22 +84,50 @@ typedef struct _GdkPixbufAnimationClass GdkPixbufAnimationClass;
 struct _GdkPixbufAnimation {
         GObject parent_instance;
 
-       /* Number of frames */
-        int n_frames;
-
-       /* List of GdkPixbufFrame structures */
-        GList *frames;
-
-       /* bounding box size */
-       int width, height;
 };
 
 struct _GdkPixbufAnimationClass {
         GObjectClass parent_class;
 
+        gboolean                (*is_static_image)  (GdkPixbufAnimation *anim);
+
+        GdkPixbuf*              (*get_static_image) (GdkPixbufAnimation *anim);
+        
+        void                    (*get_size) (GdkPixbufAnimation *anim,
+                                             int                 *width,
+                                             int                 *height);
+        
+        GdkPixbufAnimationIter* (*get_iter) (GdkPixbufAnimation *anim,
+                                             const GTimeVal     *start_time);
+
+};
+
+\f
+
+typedef struct _GdkPixbufAnimationIterClass GdkPixbufAnimationIterClass;
+
+#define GDK_PIXBUF_ANIMATION_ITER_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_PIXBUF_ANIMATION_ITER, GdkPixbufAnimationIterClass))
+#define GDK_IS_PIXBUF_ANIMATION_ITER_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_PIXBUF_ANIMATION_ITER))
+#define GDK_PIXBUF_ANIMATION_ITER_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_PIXBUF_ANIMATION_ITER, GdkPixbufAnimationIterClass))
+
+struct _GdkPixbufAnimationIter {
+        GObject parent_instance;
 
 };
 
+struct _GdkPixbufAnimationIterClass {
+        GObjectClass parent_class;
+
+        int        (*get_delay_time)   (GdkPixbufAnimationIter *iter);
+
+        GdkPixbuf* (*get_pixbuf)       (GdkPixbufAnimationIter *iter);
+
+        gboolean (*on_currently_loading_frame) (GdkPixbufAnimationIter *iter);
+
+        gboolean (*advance)            (GdkPixbufAnimationIter *iter,
+                                        const GTimeVal         *current_time);
+};
+      
 \f
 
 #define GDK_PIXBUF_INLINE_MAGIC_NUMBER 0x47646B50 /* 'GdkP' */
@@ -125,6 +138,8 @@ typedef enum
   GDK_PIXBUF_INLINE_RLE = 1
 } GdkPixbufInlineFormat;
 
+\f
 
+GdkPixbufAnimation* gdk_pixbuf_non_anim_new (GdkPixbuf *pixbuf);
 
 #endif
index bee4fb5bb77bccb118b90317fd573ee46edffc8a..0f869b94716f11ba786b36ce5b3013b787378a9c 100644 (file)
@@ -121,6 +121,8 @@ gdk_pixbuf_copy_area (const GdkPixbuf *src_pixbuf,
        g_return_if_fail (dest_x >= 0 && dest_x + width <= dest_pixbuf->width);
        g_return_if_fail (dest_y >= 0 && dest_y + height <= dest_pixbuf->height);
 
+        g_return_if_fail (!(gdk_pixbuf_get_has_alpha (src_pixbuf) && !gdk_pixbuf_get_has_alpha (dest_pixbuf)));
+        
        /* This will perform format conversions automatically */
 
        gdk_pixbuf_scale (src_pixbuf,
index 12b8e61441623a1dececc2b26f2e8990a496edbf..cfc0bb323c5e8b7420fa59e67cffcde03480f528 100644 (file)
@@ -412,7 +412,7 @@ gdk_pixbuf_error_quark (void)
 /**
  * gdk_pixbuf_fill:
  * @pixbuf: a #GdkPixbuf
- * @pixel: RGBA pixel to clear to (0xffffff00 is opaque white, 0x000000ff transparent black)
+ * @pixel: RGBA pixel to clear to (0xffffffff is opaque white, 0x00000000 transparent black)
  *
  * Clears a pixbuf to the given RGBA value, converting the RGBA value into
  * the pixbuf's pixel format. The alpha will be ignored if the pixbuf
@@ -454,7 +454,7 @@ gdk_pixbuf_fill (GdkPixbuf *pixbuf,
                 
                 p = pixels;
                 end = pixels + pixbuf->rowstride * pixbuf->height;
-                end -= (pixbuf->rowstride - pixbuf->width);
+                end -= (pixbuf->rowstride - pixbuf->width * pixbuf->n_channels);
                 
                 while (p < end) {
                         *p++ = r;
index b8b5a03af06c5a044ce879aa43e57a0bf9ef8d96..46ff3533ce9795f9ca26758219ee58c967a53c6e 100644 (file)
@@ -54,6 +54,7 @@ typedef enum {
 /* All of these are opaque structures */
 typedef struct _GdkPixbuf GdkPixbuf;
 typedef struct _GdkPixbufAnimation GdkPixbufAnimation;
+typedef struct _GdkPixbufAnimationIter GdkPixbufAnimationIter;
 typedef struct _GdkPixbufFrame GdkPixbufFrame;
 
 #define GDK_TYPE_PIXBUF              (gdk_pixbuf_get_type ())
@@ -64,6 +65,9 @@ typedef struct _GdkPixbufFrame GdkPixbufFrame;
 #define GDK_PIXBUF_ANIMATION(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_PIXBUF_ANIMATION, GdkPixbufAnimation))
 #define GDK_IS_PIXBUF_ANIMATION(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_PIXBUF_ANIMATION))
 
+#define GDK_TYPE_PIXBUF_ANIMATION_ITER              (gdk_pixbuf_animation_iter_get_type ())
+#define GDK_PIXBUF_ANIMATION_ITER(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_PIXBUF_ANIMATION_ITER, GdkPixbufAnimationIter))
+#define GDK_IS_PIXBUF_ANIMATION_ITER(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_PIXBUF_ANIMATION_ITER))
 
 /* Handler that must free the pixel array */
 typedef void (* GdkPixbufDestroyNotify) (guchar *pixels, gpointer data);
@@ -255,13 +259,6 @@ GdkPixbuf *gdk_pixbuf_composite_color_simple (const GdkPixbuf *src,
 
 /* Animation support */
 
-/* GIF-like animation overlay modes for frames */
-typedef enum {
-       GDK_PIXBUF_FRAME_RETAIN,
-       GDK_PIXBUF_FRAME_DISPOSE,
-       GDK_PIXBUF_FRAME_REVERT
-} GdkPixbufFrameAction;
-
 GType               gdk_pixbuf_animation_get_type        (void) G_GNUC_CONST;
 
 GdkPixbufAnimation *gdk_pixbuf_animation_new_from_file   (const char         *filename,
@@ -272,21 +269,20 @@ void                gdk_pixbuf_animation_unref           (GdkPixbufAnimation *an
 
 int                 gdk_pixbuf_animation_get_width       (GdkPixbufAnimation *animation);
 int                 gdk_pixbuf_animation_get_height      (GdkPixbufAnimation *animation);
-GList              *gdk_pixbuf_animation_get_frames      (GdkPixbufAnimation *animation);
-int                 gdk_pixbuf_animation_get_num_frames  (GdkPixbufAnimation *animation);
+gboolean            gdk_pixbuf_animation_is_static_image  (GdkPixbufAnimation *animation);
+GdkPixbuf          *gdk_pixbuf_animation_get_static_image (GdkPixbufAnimation *animation);
 
-/* Frame accessors */
+GdkPixbufAnimationIter *gdk_pixbuf_animation_get_iter                        (GdkPixbufAnimation     *animation,
+                                                                              const GTimeVal         *start_time);
+GType                   gdk_pixbuf_animation_iter_get_type                   (void) G_GNUC_CONST;
+int                     gdk_pixbuf_animation_iter_get_delay_time             (GdkPixbufAnimationIter *iter);
+GdkPixbuf              *gdk_pixbuf_animation_iter_get_pixbuf                 (GdkPixbufAnimationIter *iter);
+gboolean                gdk_pixbuf_animation_iter_on_currently_loading_frame (GdkPixbufAnimationIter *iter);
+gboolean                gdk_pixbuf_animation_iter_advance                    (GdkPixbufAnimationIter *iter,
+                                                                              const GTimeVal         *current_time);
 
-GdkPixbuf           *gdk_pixbuf_frame_get_pixbuf     (GdkPixbufFrame *frame);
-int                  gdk_pixbuf_frame_get_x_offset   (GdkPixbufFrame *frame);
-int                  gdk_pixbuf_frame_get_y_offset   (GdkPixbufFrame *frame);
-int                  gdk_pixbuf_frame_get_delay_time (GdkPixbufFrame *frame);
-GdkPixbufFrameAction gdk_pixbuf_frame_get_action     (GdkPixbufFrame *frame);
-GdkPixbufFrame      *gdk_pixbuf_frame_copy           (GdkPixbufFrame *src);
-void                 gdk_pixbuf_frame_free           (GdkPixbufFrame *frame);
-GType                gdk_pixbuf_frame_get_type       (void) G_GNUC_CONST;
-#define              GDK_TYPE_PIXBUF_FRAME gdk_pixbuf_frame_get_type ()
 
 #include <gdk-pixbuf/gdk-pixbuf-loader.h>
 
 \f
index c5108bcc1df49c8508d1ee31b5f23bb210d4a966..ce112f85ac67e65fffcdc92ee7b1b5f08299b11e 100644 (file)
@@ -174,9 +174,7 @@ struct bmp_progressive_state {
 static gpointer
 gdk_pixbuf__bmp_image_begin_load(ModulePreparedNotifyFunc prepared_func,
                                 ModuleUpdatedNotifyFunc updated_func,
-                                ModuleFrameDoneNotifyFunc frame_done_func,
-                                ModuleAnimationDoneNotifyFunc
-                                anim_done_func, gpointer user_data,
+                                 gpointer user_data,
                                  GError **error);
 
 static gboolean gdk_pixbuf__bmp_image_stop_load(gpointer data, GError **error);
@@ -198,7 +196,7 @@ static GdkPixbuf *gdk_pixbuf__bmp_image_load(FILE * f, GError **error)
        GdkPixbuf *pb;
 
        State =
-           gdk_pixbuf__bmp_image_begin_load(NULL, NULL, NULL, NULL, NULL,
+           gdk_pixbuf__bmp_image_begin_load(NULL, NULL, NULL,
                                              error);
 
         if (State == NULL)
@@ -312,7 +310,7 @@ static gboolean DecodeHeader(unsigned char *BFH, unsigned char *BIH,
                 
                if (State->prepared_func != NULL)
                        /* Notify the client that we are ready to go */
-                       (*State->prepared_func) (State->pixbuf, State->user_data);
+                       (*State->prepared_func) (State->pixbuf, NULL, State->user_data);
 
        }
 
@@ -328,9 +326,7 @@ static gboolean DecodeHeader(unsigned char *BFH, unsigned char *BIH,
 static gpointer
 gdk_pixbuf__bmp_image_begin_load(ModulePreparedNotifyFunc prepared_func,
                                 ModuleUpdatedNotifyFunc updated_func,
-                                ModuleFrameDoneNotifyFunc frame_done_func,
-                                ModuleAnimationDoneNotifyFunc
-                                anim_done_func, gpointer user_data,
+                                 gpointer user_data,
                                  GError **error)
 {
        struct bmp_progressive_state *context;
diff --git a/gdk-pixbuf/io-gif-animation.c b/gdk-pixbuf/io-gif-animation.c
new file mode 100644 (file)
index 0000000..fe164a0
--- /dev/null
@@ -0,0 +1,557 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/* GdkPixbuf library - animated gif support
+ *
+ * Copyright (C) 1999 The Free Software Foundation
+ *
+ * Authors: Jonathan Blandford <jrb@redhat.com>
+ *          Havoc Pennington <hp@redhat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+#include <errno.h>
+#include "gdk-pixbuf-io.h"
+#include "gdk-pixbuf-private.h"
+#include "io-gif-animation.h"
+
+static void gdk_pixbuf_gif_anim_class_init (GdkPixbufGifAnimClass *klass);
+static void gdk_pixbuf_gif_anim_finalize   (GObject        *object);
+
+static gboolean                gdk_pixbuf_gif_anim_is_static_image  (GdkPixbufAnimation *animation);
+static GdkPixbuf*              gdk_pixbuf_gif_anim_get_static_image (GdkPixbufAnimation *animation);
+
+static void                    gdk_pixbuf_gif_anim_get_size (GdkPixbufAnimation *anim,
+                                                             int                *width,
+                                                             int                *height);
+static GdkPixbufAnimationIter* gdk_pixbuf_gif_anim_get_iter (GdkPixbufAnimation *anim,
+                                                             const GTimeVal     *start_time);
+
+
+\f
+
+static gpointer parent_class;
+
+GType
+gdk_pixbuf_gif_anim_get_type (void)
+{
+        static GType object_type = 0;
+
+        if (!object_type) {
+                static const GTypeInfo object_info = {
+                        sizeof (GdkPixbufGifAnimClass),
+                        (GBaseInitFunc) NULL,
+                        (GBaseFinalizeFunc) NULL,
+                        (GClassInitFunc) gdk_pixbuf_gif_anim_class_init,
+                        NULL,           /* class_finalize */
+                        NULL,           /* class_data */
+                        sizeof (GdkPixbufGifAnim),
+                        0,              /* n_preallocs */
+                        (GInstanceInitFunc) NULL,
+                };
+                
+                object_type = g_type_register_static (GDK_TYPE_PIXBUF_ANIMATION,
+                                                      "GdkPixbufGifAnim",
+                                                      &object_info, 0);
+        }
+        
+        return object_type;
+}
+
+static void
+gdk_pixbuf_gif_anim_class_init (GdkPixbufGifAnimClass *klass)
+{
+        GObjectClass *object_class = G_OBJECT_CLASS (klass);
+        GdkPixbufAnimationClass *anim_class = GDK_PIXBUF_ANIMATION_CLASS (klass);
+        
+        parent_class = g_type_class_peek_parent (klass);
+        
+        object_class->finalize = gdk_pixbuf_gif_anim_finalize;
+
+        anim_class->is_static_image = gdk_pixbuf_gif_anim_is_static_image;
+        anim_class->get_static_image = gdk_pixbuf_gif_anim_get_static_image;
+        anim_class->get_size = gdk_pixbuf_gif_anim_get_size;
+        anim_class->get_iter = gdk_pixbuf_gif_anim_get_iter;
+}
+
+static void
+gdk_pixbuf_gif_anim_finalize (GObject *object)
+{
+        GdkPixbufGifAnim *gif_anim = GDK_PIXBUF_GIF_ANIM (object);
+
+        GList *l;
+        GdkPixbufFrame *frame;
+        
+        for (l = gif_anim->frames; l; l = l->next) {
+                frame = l->data;
+                gdk_pixbuf_unref (frame->pixbuf);
+                if (frame->composited)
+                        gdk_pixbuf_unref (frame->composited);
+                if (frame->revert)
+                        gdk_pixbuf_unref (frame->revert);
+                g_free (frame);
+        }
+        
+        g_list_free (gif_anim->frames);
+        
+        G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static gboolean
+gdk_pixbuf_gif_anim_is_static_image  (GdkPixbufAnimation *animation)
+{
+        GdkPixbufGifAnim *gif_anim;
+
+        gif_anim = GDK_PIXBUF_GIF_ANIM (animation);
+
+        return (gif_anim->frames != NULL &&
+                gif_anim->frames->next == NULL);
+}
+
+static GdkPixbuf*
+gdk_pixbuf_gif_anim_get_static_image (GdkPixbufAnimation *animation)
+{
+        GdkPixbufGifAnim *gif_anim;
+
+        gif_anim = GDK_PIXBUF_GIF_ANIM (animation);
+
+        if (gif_anim->frames == NULL)
+                return NULL;
+        else
+                return GDK_PIXBUF (((GdkPixbufFrame*)gif_anim->frames->data)->pixbuf);        
+}
+
+static void
+gdk_pixbuf_gif_anim_get_size (GdkPixbufAnimation *anim,
+                              int                *width,
+                              int                *height)
+{
+        GdkPixbufGifAnim *gif_anim;
+
+        gif_anim = GDK_PIXBUF_GIF_ANIM (anim);
+
+        if (width)
+                *width = gif_anim->width;
+
+        if (height)
+                *height = gif_anim->height;
+}
+
+
+static void
+iter_clear (GdkPixbufGifAnimIter *iter)
+{
+        iter->current_frame = NULL;
+}
+
+static void
+iter_restart (GdkPixbufGifAnimIter *iter)
+{
+        iter_clear (iter);
+  
+        iter->current_frame = iter->gif_anim->frames;
+}
+
+static GdkPixbufAnimationIter*
+gdk_pixbuf_gif_anim_get_iter (GdkPixbufAnimation *anim,
+                              const GTimeVal     *start_time)
+{
+        GdkPixbufGifAnimIter *iter;
+
+        iter = g_object_new (GDK_TYPE_PIXBUF_GIF_ANIM_ITER, NULL);
+
+        iter->gif_anim = GDK_PIXBUF_GIF_ANIM (anim);
+
+        g_object_ref (G_OBJECT (iter->gif_anim));
+        
+        iter_restart (iter);
+
+        iter->start_time = *start_time;
+        iter->current_time = *start_time;
+        
+        return GDK_PIXBUF_ANIMATION_ITER (iter);
+}
+
+\f
+
+static void gdk_pixbuf_gif_anim_iter_class_init (GdkPixbufGifAnimIterClass *klass);
+static void gdk_pixbuf_gif_anim_iter_finalize   (GObject                   *object);
+
+static int        gdk_pixbuf_gif_anim_iter_get_delay_time             (GdkPixbufAnimationIter *iter);
+static GdkPixbuf* gdk_pixbuf_gif_anim_iter_get_pixbuf                 (GdkPixbufAnimationIter *iter);
+static gboolean   gdk_pixbuf_gif_anim_iter_on_currently_loading_frame (GdkPixbufAnimationIter *iter);
+static gboolean   gdk_pixbuf_gif_anim_iter_advance                    (GdkPixbufAnimationIter *iter,
+                                                                       const GTimeVal         *current_time);
+
+\f
+
+static gpointer iter_parent_class;
+
+GType
+gdk_pixbuf_gif_anim_iter_get_type (void)
+{
+        static GType object_type = 0;
+
+        if (!object_type) {
+                static const GTypeInfo object_info = {
+                        sizeof (GdkPixbufGifAnimIterClass),
+                        (GBaseInitFunc) NULL,
+                        (GBaseFinalizeFunc) NULL,
+                        (GClassInitFunc) gdk_pixbuf_gif_anim_iter_class_init,
+                        NULL,           /* class_finalize */
+                        NULL,           /* class_data */
+                        sizeof (GdkPixbufGifAnimIter),
+                        0,              /* n_preallocs */
+                        (GInstanceInitFunc) NULL,
+                };
+                
+                object_type = g_type_register_static (GDK_TYPE_PIXBUF_ANIMATION_ITER,
+                                                      "GdkPixbufGifAnimIter",
+                                                      &object_info, 0);
+        }
+        
+        return object_type;
+}
+
+static void
+gdk_pixbuf_gif_anim_iter_class_init (GdkPixbufGifAnimIterClass *klass)
+{
+        GObjectClass *object_class = G_OBJECT_CLASS (klass);
+        GdkPixbufAnimationIterClass *anim_iter_class =
+                GDK_PIXBUF_ANIMATION_ITER_CLASS (klass);
+        
+        iter_parent_class = g_type_class_peek_parent (klass);
+        
+        object_class->finalize = gdk_pixbuf_gif_anim_iter_finalize;
+
+        anim_iter_class->get_delay_time = gdk_pixbuf_gif_anim_iter_get_delay_time;
+        anim_iter_class->get_pixbuf = gdk_pixbuf_gif_anim_iter_get_pixbuf;
+        anim_iter_class->on_currently_loading_frame = gdk_pixbuf_gif_anim_iter_on_currently_loading_frame;
+        anim_iter_class->advance = gdk_pixbuf_gif_anim_iter_advance;
+}
+
+static void
+gdk_pixbuf_gif_anim_iter_finalize (GObject *object)
+{
+        GdkPixbufGifAnimIter *iter = GDK_PIXBUF_GIF_ANIM_ITER (object);
+
+        iter_clear (iter);
+
+        g_object_unref (G_OBJECT (iter->gif_anim));
+        
+        G_OBJECT_CLASS (iter_parent_class)->finalize (object);
+}
+
+static gboolean
+gdk_pixbuf_gif_anim_iter_advance (GdkPixbufAnimationIter *anim_iter,
+                                  const GTimeVal         *current_time)
+{
+        GdkPixbufGifAnimIter *iter;
+        gint elapsed;
+        GList *tmp;
+        GList *old;
+        
+        iter = GDK_PIXBUF_GIF_ANIM_ITER (anim_iter);
+        
+        iter->current_time = *current_time;
+
+        /* We use milliseconds for all times */
+        elapsed =
+          (((iter->current_time.tv_sec - iter->start_time.tv_sec) * G_USEC_PER_SEC +
+            iter->current_time.tv_usec - iter->start_time.tv_usec)) / 1000;
+        
+        if (elapsed < 0) {
+                /* Try to compensate; probably the system clock
+                 * was set backwards
+                 */
+                iter->start_time = iter->current_time;
+                elapsed = 0;
+        }
+        
+        /* See how many times we've already played the full animation,
+         * and subtract time for that.
+         */
+        elapsed = elapsed % iter->gif_anim->total_time;
+
+        g_assert (elapsed < iter->gif_anim->total_time);
+
+        iter->position = elapsed;
+        
+        /* Now move to the proper frame */
+        tmp = iter->gif_anim->frames;
+        while (tmp != NULL) {
+                GdkPixbufFrame *frame = tmp->data;
+                
+                if (iter->position >= frame->elapsed &&
+                    iter->position < (frame->elapsed + frame->delay_time))
+                        break;
+                
+                tmp = tmp->next;
+        }
+
+        old = iter->current_frame;
+        
+        iter->current_frame = tmp;
+
+        return iter->current_frame != old;
+}
+
+int
+gdk_pixbuf_gif_anim_iter_get_delay_time (GdkPixbufAnimationIter *anim_iter)
+{
+        GdkPixbufFrame *frame;
+        GdkPixbufGifAnimIter *iter;
+  
+        iter = GDK_PIXBUF_GIF_ANIM_ITER (anim_iter);
+
+        if (iter->current_frame) {
+                frame = iter->current_frame->data;
+
+#if 0
+                g_print ("frame start: %d pos: %d frame len: %d frame remaining: %d\n",
+                         frame->elapsed,
+                         iter->position,
+                         frame->delay_time,
+                         frame->delay_time - (iter->position - frame->elapsed));
+#endif
+                
+                return frame->delay_time - (iter->position - frame->elapsed);
+        } else {
+                return -1; /* show last frame forever */
+        }
+}
+
+void
+gdk_pixbuf_gif_anim_frame_composite (GdkPixbufGifAnim *gif_anim,
+                                     GdkPixbufFrame   *frame)
+{  
+        GList *link;
+        GList *tmp;
+        
+        link = g_list_find (gif_anim->frames, frame);
+        
+        if (frame->need_recomposite || frame->composited == NULL) {
+                /* For now, to composite we start with the last
+                 * composited frame and composite everything up to
+                 * here.
+                 */
+
+                /* Rewind to last composited frame. */
+                tmp = link;
+                while (tmp != NULL) {
+                        GdkPixbufFrame *f = tmp->data;
+                        
+                        if (f->need_recomposite) {
+                                if (f->composited) {
+                                        g_object_unref (G_OBJECT (f->composited));
+                                        f->composited = NULL;
+                                }
+                        }
+
+                        if (f->composited != NULL)
+                                break;
+                        
+                        tmp = tmp->prev;
+                }
+
+                /* Go forward, compositing all frames up to the current frame */
+                if (tmp == NULL)
+                        tmp = gif_anim->frames;
+                
+                while (tmp != NULL) {
+                        GdkPixbufFrame *f = tmp->data;
+
+                        if (f->need_recomposite) {
+                                if (f->composited) {
+                                        g_object_unref (G_OBJECT (f->composited));
+                                        f->composited = NULL;
+                                }
+                        }
+                        
+                        if (f->composited != NULL)
+                                goto next;
+
+                        if (tmp->prev == NULL) {
+                                /* First frame may be smaller than the whole image;
+                                 * if so, we make the area outside it full alpha if the
+                                 * image has alpha, and background color otherwise.
+                                 * GIF spec doesn't actually say what to do about this.
+                                 */
+                                f->composited = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
+                                                                TRUE,
+                                                                8, gif_anim->width, gif_anim->height);
+
+                                /* alpha gets dumped if f->composited has no alpha */
+                                
+                                gdk_pixbuf_fill (f->composited,
+                                                 (gif_anim->bg_red << 24) |
+                                                 (gif_anim->bg_green << 16) |
+                                                 (gif_anim->bg_blue << 8) |
+                                                 (f->bg_transparent ? 0 : 255));
+
+                                gdk_pixbuf_composite (f->pixbuf,
+                                                      f->composited,
+                                                      f->x_offset,
+                                                      f->y_offset,
+                                                      gdk_pixbuf_get_width (f->pixbuf),
+                                                      gdk_pixbuf_get_height (f->pixbuf),
+                                                      f->x_offset, f->y_offset,
+                                                      1.0, 1.0,
+                                                      GDK_INTERP_BILINEAR,
+                                                      255);
+#if 0                                
+                                gdk_pixbuf_copy_area (f->pixbuf,
+                                                      0, 0,
+                                                      gdk_pixbuf_get_width (f->pixbuf),
+                                                      gdk_pixbuf_get_height (f->pixbuf),
+                                                      f->composited,
+                                                      f->x_offset,
+                                                      f->y_offset);
+                                
+#endif
+                                
+                                if (f->action == GDK_PIXBUF_FRAME_REVERT)
+                                        g_warning ("First frame of GIF has bad dispose mode, GIF loader should not have loaded this image");
+
+                                f->need_recomposite = FALSE;
+                        } else {
+                                GdkPixbufFrame *prev_frame;
+                                
+                                prev_frame = tmp->prev->data;
+
+                                /* Init f->composited with what we should have after the previous
+                                 * frame
+                                 */
+                                
+                                if (prev_frame->action == GDK_PIXBUF_FRAME_RETAIN) {
+                                        f->composited = gdk_pixbuf_copy (prev_frame->composited);
+                                        
+                                } else if (prev_frame->action == GDK_PIXBUF_FRAME_DISPOSE) {
+                                        GdkPixbuf *area;
+                                        
+                                        f->composited = gdk_pixbuf_copy (prev_frame->composited);
+
+                                        /* Clear area of previous frame to background */
+                                        area = gdk_pixbuf_new_subpixbuf (f->composited,
+                                                                         prev_frame->x_offset,
+                                                                         prev_frame->y_offset,
+                                                                         gdk_pixbuf_get_width (prev_frame->pixbuf),
+                                                                         gdk_pixbuf_get_height (prev_frame->pixbuf));
+
+                                        gdk_pixbuf_fill (area,
+                                                         (gif_anim->bg_red << 24) |
+                                                         (gif_anim->bg_green << 16) |
+                                                         (gif_anim->bg_blue << 8) |
+                                                         prev_frame->bg_transparent ? 0 : 255);
+
+                                        g_object_unref (G_OBJECT (area));
+                                        
+                                } else if (prev_frame->action == GDK_PIXBUF_FRAME_REVERT) {
+                                        f->composited = gdk_pixbuf_copy (prev_frame->composited);
+
+                                        /* Copy in the revert frame */
+                                        gdk_pixbuf_copy_area (prev_frame->revert,
+                                                              0, 0,
+                                                              gdk_pixbuf_get_width (prev_frame->revert),
+                                                              gdk_pixbuf_get_height (prev_frame->revert),
+                                                              f->composited,
+                                                              prev_frame->x_offset,
+                                                              prev_frame->y_offset);
+                                } else {
+                                        g_warning ("Unknown revert action for GIF frame");
+                                }
+
+                                if (f->revert == NULL &&
+                                    f->action == GDK_PIXBUF_FRAME_REVERT) {
+                                        /* We need to save the contents before compositing */
+                                        GdkPixbuf *area;
+
+                                        area = gdk_pixbuf_new_subpixbuf (f->composited,
+                                                                         f->x_offset,
+                                                                         f->y_offset,
+                                                                         gdk_pixbuf_get_width (f->pixbuf),
+                                                                         gdk_pixbuf_get_height (f->pixbuf));
+
+                                        f->revert = gdk_pixbuf_copy (area);
+                                        
+                                        g_object_unref (G_OBJECT (area));
+                                }
+
+                                /* Put current frame onto f->composited */
+                                gdk_pixbuf_composite (f->pixbuf,
+                                                      f->composited,
+                                                      f->x_offset,
+                                                      f->y_offset,
+                                                      gdk_pixbuf_get_width (f->pixbuf),
+                                                      gdk_pixbuf_get_height (f->pixbuf),
+                                                      f->x_offset, f->y_offset,
+                                                      1.0, 1.0,
+                                                      GDK_INTERP_NEAREST,
+                                                      255);
+                        
+                                f->need_recomposite = FALSE;
+                        }
+                        
+                next:
+                        if (tmp == link)
+                                break;
+                        
+                        tmp = tmp->next;
+                }
+        }
+
+        g_assert (frame->composited != NULL);
+        g_assert (gdk_pixbuf_get_width (frame->composited) == gif_anim->width);
+        g_assert (gdk_pixbuf_get_height (frame->composited) == gif_anim->height);
+}
+
+GdkPixbuf*
+gdk_pixbuf_gif_anim_iter_get_pixbuf (GdkPixbufAnimationIter *anim_iter)
+{
+        GdkPixbufGifAnimIter *iter;
+        GdkPixbufFrame *frame;
+        
+        iter = GDK_PIXBUF_GIF_ANIM_ITER (anim_iter);
+
+        frame = iter->current_frame ? iter->current_frame->data : NULL;
+
+#if 0
+        if (FALSE && frame)
+          g_print ("current frame %d dispose mode %d  %d x %d\n",
+                   g_list_index (iter->gif_anim->frames,
+                                 frame),
+                   frame->action,
+                   gdk_pixbuf_get_width (frame->pixbuf),
+                   gdk_pixbuf_get_height (frame->pixbuf));
+#endif
+        
+        if (frame == NULL)
+                return NULL;
+
+        gdk_pixbuf_gif_anim_frame_composite (iter->gif_anim, frame);
+        
+        return frame->composited;
+}
+
+static gboolean
+gdk_pixbuf_gif_anim_iter_on_currently_loading_frame (GdkPixbufAnimationIter *anim_iter)
+{
+        GdkPixbufGifAnimIter *iter;
+  
+        iter = GDK_PIXBUF_GIF_ANIM_ITER (anim_iter);
+
+        return iter->current_frame == NULL || iter->current_frame->next == NULL;  
+}
diff --git a/gdk-pixbuf/io-gif-animation.h b/gdk-pixbuf/io-gif-animation.h
new file mode 100644 (file)
index 0000000..ce1ebaa
--- /dev/null
@@ -0,0 +1,169 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/* GdkPixbuf library - GIF loader declarations
+ *
+ * Copyright (C) 1999 The Free Software Foundation
+ *
+ * Authors: Mark Crichton <crichton@gimp.org>
+ *          Miguel de Icaza <miguel@gnu.org>
+ *          Federico Mena-Quintero <federico@gimp.org>
+ *          Havoc Pennington <hp@redhat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef GDK_PIXBUF_GIF_H
+#define GDK_PIXBUF_GIF_H
+
+#include "gdk-pixbuf-private.h"
+
+typedef enum {
+        /* Keep this frame and composite next frame over it */
+        /* (GIF disposal method 1) */
+       GDK_PIXBUF_FRAME_RETAIN,
+        /* Revert to background color before compositing next frame */
+        /* (GIF disposal method 2) */
+       GDK_PIXBUF_FRAME_DISPOSE,
+        /* Revert to previously-displayed composite image after
+         * displaying this frame
+         */
+        /* (GIF disposal method 3) */
+       GDK_PIXBUF_FRAME_REVERT
+} GdkPixbufFrameAction;
+
+\f
+
+typedef struct _GdkPixbufGifAnim GdkPixbufGifAnim;
+typedef struct _GdkPixbufGifAnimClass GdkPixbufGifAnimClass;
+
+#define GDK_TYPE_PIXBUF_GIF_ANIM              (gdk_pixbuf_gif_anim_get_type ())
+#define GDK_PIXBUF_GIF_ANIM(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_PIXBUF_GIF_ANIM, GdkPixbufGifAnim))
+#define GDK_IS_PIXBUF_GIF_ANIM(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_PIXBUF_GIF_ANIM))
+
+#define GDK_PIXBUF_GIF_ANIM_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_PIXBUF_GIF_ANIM, GdkPixbufGifAnimClass))
+#define GDK_IS_PIXBUF_GIF_ANIM_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_PIXBUF_GIF_ANIM))
+#define GDK_PIXBUF_GIF_ANIM_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_PIXBUF_GIF_ANIM, GdkPixbufGifAnimClass))
+
+/* Private part of the GdkPixbufGifAnim structure */
+struct _GdkPixbufGifAnim {
+        GdkPixbufAnimation parent_instance;
+
+        /* Number of frames */
+        int n_frames;
+
+        /* Total length of animation */
+        int total_time;
+        
+       /* List of GdkPixbufFrame structures */
+        GList *frames;
+
+       /* bounding box size */
+       int width, height;
+
+        guchar bg_red;
+        guchar bg_green;
+        guchar bg_blue;
+};
+
+struct _GdkPixbufGifAnimClass {
+        GdkPixbufAnimationClass parent_class;
+        
+};
+
+GType gdk_pixbuf_gif_anim_get_type (void) G_GNUC_CONST;
+
+\f
+
+typedef struct _GdkPixbufGifAnimIter GdkPixbufGifAnimIter;
+typedef struct _GdkPixbufGifAnimIterClass GdkPixbufGifAnimIterClass;
+
+
+#define GDK_TYPE_PIXBUF_GIF_ANIM_ITER              (gdk_pixbuf_gif_anim_iter_get_type ())
+#define GDK_PIXBUF_GIF_ANIM_ITER(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_PIXBUF_GIF_ANIM_ITER, GdkPixbufGifAnimIter))
+#define GDK_IS_PIXBUF_GIF_ANIM_ITER(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_PIXBUF_GIF_ANIM_ITER))
+
+#define GDK_PIXBUF_GIF_ANIM_ITER_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_PIXBUF_GIF_ANIM_ITER, GdkPixbufGifAnimIterClass))
+#define GDK_IS_PIXBUF_GIF_ANIM_ITER_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_PIXBUF_GIF_ANIM_ITER))
+#define GDK_PIXBUF_GIF_ANIM_ITER_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_PIXBUF_GIF_ANIM_ITER, GdkPixbufGifAnimIterClass))
+
+struct _GdkPixbufGifAnimIter {
+        GdkPixbufAnimationIter parent_instance;
+        
+        GdkPixbufGifAnim   *gif_anim;
+
+        GTimeVal            start_time;
+        GTimeVal            current_time;
+
+        /* Time in milliseconds into this run of the animation */
+        gint                position;
+        
+        GList              *current_frame;
+};
+
+struct _GdkPixbufGifAnimIterClass {
+        GdkPixbufAnimationIterClass parent_class;
+
+};
+
+GType gdk_pixbuf_gif_anim_iter_get_type (void) G_GNUC_CONST;
+
+\f
+
+struct _GdkPixbufFrame {
+       /* The pixbuf with this frame's image data */
+       GdkPixbuf *pixbuf;
+
+        /* Offsets for overlaying onto the GIF graphic area */
+        int x_offset;
+       int y_offset;
+
+       /* Frame duration in ms */
+       int delay_time;
+
+        /* Sum of preceding delay times */
+        int elapsed;
+        
+        /* Overlay mode */
+       GdkPixbufFrameAction action;
+
+        /* TRUE if the pixbuf has been modified since
+         * the last frame composite operation
+         */
+        gboolean need_recomposite;
+
+        /* TRUE if the background for this frame is transparent */
+        gboolean bg_transparent;
+        
+        /* The below reflects the "use hell of a lot of RAM"
+         * philosophy of coding
+         */
+        
+        /* Cached composite image (the image you actually display
+         * for this frame)
+         */
+        GdkPixbuf *composited;
+
+        /* Cached revert image (the contents of the area
+         * covered by the frame prior to compositing;
+         * same size as pixbuf, not as the composite image; only
+         * used for FRAME_REVERT frames)
+         */
+        GdkPixbuf *revert;
+};
+
+void gdk_pixbuf_gif_anim_frame_composite (GdkPixbufGifAnim *gif_anim,
+                                          GdkPixbufFrame   *frame);
+
+#endif
index 5be68023fca39605ef7b866c4ed5bf51978ea89c..c3c1b8728c50a175896760ba9b722e154dd48fc3 100644 (file)
@@ -1,3 +1,4 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
 /* GdkPixbuf library - GIF image loader
  *
  * Copyright (C) 1999 Mark Crichton
  * in it got a bit messy.  Basicly, every function is written to expect a failed
  * read_gif, and lets you call it again assuming that the bytes are there.
  *
- * A note on Animations:
- * Currently, it doesn't correctly read the different colormap per frame.  This
- * needs implementing sometime.
- *
  * Return vals.
  * Unless otherwise specified, these are the return vals for most functions:
  *
 #include <config.h>
 #include <stdio.h>
 #include <string.h>
+#include <errno.h>
 #include "gdk-pixbuf-private.h"
 #include "gdk-pixbuf-io.h"
+#include "io-gif-animation.h"
 
 \f
 
+#undef DUMP_IMAGE_DETAILS
+
 #define MAXCOLORMAPSIZE  256
 #define MAX_LZW_BITS     12
 
@@ -88,7 +89,7 @@ enum {
        GIF_LZW_FILL_BUFFER,
        GIF_LZW_CLEAR_CODE,
        GIF_GET_LZW,
-       GIF_DONE,
+       GIF_DONE
 };
 
 
@@ -107,19 +108,27 @@ struct _GifContext
        int state; /* really only relevant for progressive loading */
        unsigned int width;
        unsigned int height;
-       CMap color_map;
-       CMap frame_color_map;
-       unsigned int bit_pixel;
-       unsigned int color_resolution;
-       unsigned int background;
+
+        gboolean has_global_cmap;
+
+        CMap global_color_map;
+        gint global_colormap_size;
+        unsigned int global_bit_pixel;
+       unsigned int global_color_resolution;
+        unsigned int background_index;
+
+        gboolean frame_cmap_active;
+        CMap frame_color_map;
+        gint frame_colormap_size;
+        unsigned int frame_bit_pixel;
+
        unsigned int aspect_ratio;
        GdkPixbuf *pixbuf;
-       GdkPixbufAnimation *animation;
+       GdkPixbufGifAnim *animation;
        GdkPixbufFrame *frame;
        Gif89 gif89;
 
-       /* stuff per frame.  As we only support the first one, not so
-        * relevant.  But still needed */
+       /* stuff per frame. */
        int frame_len;
        int frame_height;
        int frame_interlace;
@@ -132,18 +141,12 @@ struct _GifContext
        /* progressive read, only. */
        ModulePreparedNotifyFunc prepare_func;
        ModuleUpdatedNotifyFunc update_func;
-       ModuleFrameDoneNotifyFunc frame_done_func;
-       ModuleAnimationDoneNotifyFunc anim_done_func;
        gpointer user_data;
         guchar *buf;
        guint ptr;
        guint size;
        guint amount_needed;
 
-       /* colormap context */
-       gint colormap_index;
-       gint colormap_flag;
-
        /* extension context */
        guchar extension_label;
        guchar extension_flag;
@@ -207,7 +210,14 @@ gif_read (GifContext *context, guchar *buffer, size_t len)
                count += len;
                g_print ("Fsize :%d\tcount :%d\t", len, count);
 #endif
-               retval = (fread(buffer, len, 1, context->file) != 0);                
+               retval = (fread(buffer, len, 1, context->file) != 0);
+
+                if (!retval && ferror (context->file))
+                        g_set_error (context->error,
+                                     G_FILE_ERROR,
+                                     g_file_error_from_errno (errno),
+                                     _("Failure reading GIF: %s"), strerror (errno));
+                
 #ifdef IO_GIFDEBUG
                if (len < 100) {
                        for (i = 0; i < len; i++)
@@ -247,16 +257,14 @@ gif_read (GifContext *context, guchar *buffer, size_t len)
 static void
 gif_set_get_colormap (GifContext *context)
 {
-       context->colormap_flag = TRUE;
-       context->colormap_index = 0;
+       context->global_colormap_size = 0;
        context->state = GIF_GET_COLORMAP;
 }
 
 static void
 gif_set_get_colormap2 (GifContext *context)
 {
-       context->colormap_flag = TRUE;
-       context->colormap_index = 0;
+       context->frame_colormap_size = 0;
        context->state = GIF_GET_COLORMAP2;
 }
 
@@ -265,18 +273,43 @@ gif_get_colormap (GifContext *context)
 {
        unsigned char rgb[3];
 
-       while (context->colormap_index < context->bit_pixel) {
+       while (context->global_colormap_size < context->global_bit_pixel) {
+               if (!gif_read (context, rgb, sizeof (rgb))) {
+                       return -1;
+               }
+
+               context->global_color_map[0][context->global_colormap_size] = rgb[0];
+               context->global_color_map[1][context->global_colormap_size] = rgb[1];
+               context->global_color_map[2][context->global_colormap_size] = rgb[2];
+
+                if (context->global_colormap_size == context->background_index) {
+                        context->animation->bg_red = rgb[0];
+                        context->animation->bg_green = rgb[1];
+                        context->animation->bg_blue = rgb[2];
+                }
+
+               context->global_colormap_size ++;
+       }
+
+       return 0;
+}
+
+
+static gint
+gif_get_colormap2 (GifContext *context)
+{
+       unsigned char rgb[3];
+
+       while (context->frame_colormap_size < context->frame_bit_pixel) {
                if (!gif_read (context, rgb, sizeof (rgb))) {
-                       /*g_message (_("GIF: bad colormap\n"));*/
                        return -1;
                }
 
-               context->color_map[0][context->colormap_index] = rgb[0];
-               context->color_map[1][context->colormap_index] = rgb[1];
-               context->color_map[2][context->colormap_index] = rgb[2];
+               context->frame_color_map[0][context->frame_colormap_size] = rgb[0];
+               context->frame_color_map[1][context->frame_colormap_size] = rgb[1];
+               context->frame_color_map[2][context->frame_colormap_size] = rgb[2];
 
-               context->colormap_flag &= (rgb[0] == rgb[1] && rgb[1] == rgb[2]);
-               context->colormap_index ++;
+               context->frame_colormap_size ++;
        }
 
        return 0;
@@ -348,9 +381,11 @@ gif_get_extension (GifContext *context)
                        retval = get_data_block (context, (unsigned char *) context->block_buf, NULL);
                        if (retval != 0)
                                return retval;
-                       if (context->pixbuf == NULL) {
+
+                       if (context->frame == NULL) {
                                /* I only want to set the transparency if I haven't
-                                * created the pixbuf yet. */
+                                * created the frame yet.
+                                 */
                                context->gif89.disposal = (context->block_buf[0] >> 2) & 0x7;
                                context->gif89.input_flag = (context->block_buf[0] >> 1) & 0x1;
                                context->gif89.delay_time = LM_to_uint (context->block_buf[1], context->block_buf[2]);
@@ -623,18 +658,24 @@ static void
 gif_fill_in_pixels (GifContext *context, guchar *dest, gint offset, guchar v)
 {
        guchar *pixel = NULL;
+        guchar (*cmap)[MAXCOLORMAPSIZE];
 
+        if (context->frame_cmap_active)
+                cmap = context->frame_color_map;
+        else
+                cmap = context->global_color_map;
+        
        if (context->gif89.transparent != -1) {
-               pixel = dest + (context->draw_ypos + offset) * gdk_pixbuf_get_rowstride (context->pixbuf) + context->draw_xpos * 4;
-               *pixel = context->color_map [0][(guchar) v];
-               *(pixel+1) = context->color_map [1][(guchar) v];
-               *(pixel+2) = context->color_map [2][(guchar) v];
-               *(pixel+3) = (guchar) ((v == context->gif89.transparent) ? 0 : 65535);
+               pixel = dest + (context->draw_ypos + offset) * gdk_pixbuf_get_rowstride (context->frame->pixbuf) + context->draw_xpos * 4;
+               *pixel = cmap [0][(guchar) v];
+               *(pixel+1) = cmap [1][(guchar) v];
+               *(pixel+2) = cmap [2][(guchar) v];
+               *(pixel+3) = (guchar) ((v == context->gif89.transparent) ? 0 : 255);
        } else {
-               pixel = dest + (context->draw_ypos + offset) * gdk_pixbuf_get_rowstride (context->pixbuf) + context->draw_xpos * 3;
-               *pixel = context->color_map [0][(guchar) v];
-               *(pixel+1) = context->color_map [1][(guchar) v];
-               *(pixel+2) = context->color_map [2][(guchar) v];
+               pixel = dest + (context->draw_ypos + offset) * gdk_pixbuf_get_rowstride (context->frame->pixbuf) + context->draw_xpos * 3;
+               *pixel = cmap [0][(guchar) v];
+               *(pixel+1) = cmap [1][(guchar) v];
+               *(pixel+2) = cmap [2][(guchar) v];
        }
 }
 
@@ -682,80 +723,123 @@ gif_get_lzw (GifContext *context)
        gint first_pass; /* bounds for emitting the area_updated signal */
        gint v;
 
-       if (context->pixbuf == NULL) {
-               context->pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
-                                                 context->gif89.transparent != -1,
-                                                 8,
-                                                 context->frame_len,
-                                                 context->frame_height);
-
-               if (context->prepare_func)
-                       (* context->prepare_func) (context->pixbuf, context->user_data);
-               if (context->animation || context->frame_done_func || context->anim_done_func) {
-                       context->frame = g_new (GdkPixbufFrame, 1);
-                       context->frame->x_offset = context->x_offset;
-                       context->frame->y_offset = context->y_offset;;
-                       context->frame->delay_time = context->gif89.delay_time;
-                       switch (context->gif89.disposal) {
-                       case 0:
-                       case 1:
-                               context->frame->action = GDK_PIXBUF_FRAME_RETAIN;
-                               break;
-                       case 2:
-                               context->frame->action = GDK_PIXBUF_FRAME_DISPOSE;
-                               break;
-                       case 3:
-                               context->frame->action = GDK_PIXBUF_FRAME_REVERT;
-                               break;
-                       default:
-                               context->frame->action = GDK_PIXBUF_FRAME_RETAIN;
-                               break;
-                       }
-                       context->frame->pixbuf = context->pixbuf;
-                       if (context->animation) {
-                               int w,h;
-                               context->animation->n_frames ++;
-                               context->animation->frames = g_list_append (context->animation->frames, context->frame);
-                               w = gdk_pixbuf_get_width (context->pixbuf);
-                               h = gdk_pixbuf_get_height (context->pixbuf);
-                               if (w > context->animation->width)
-                                       context->animation->width = w;
-                               if (h > context->animation->height)
-                                       context->animation->height = h;
-                       }
-               }
-       }
-       dest = gdk_pixbuf_get_pixels (context->pixbuf);
+       if (context->frame == NULL) {
+                context->frame = g_new (GdkPixbufFrame, 1);
+
+                context->frame->composited = NULL;
+                context->frame->revert = NULL;
+                
+                context->frame->pixbuf =
+                        gdk_pixbuf_new (GDK_COLORSPACE_RGB,
+                                        TRUE,
+                                        8,
+                                        context->frame_len,
+                                        context->frame_height);
+                
+                context->frame->x_offset = context->x_offset;
+                context->frame->y_offset = context->y_offset;
+                context->frame->need_recomposite = TRUE;
+                
+                /* GIF delay is in hundredths, we want thousandths */
+                context->frame->delay_time = context->gif89.delay_time * 10;
+                context->frame->elapsed = context->animation->total_time;
+                context->animation->total_time += context->frame->delay_time;
+                
+                switch (context->gif89.disposal) {
+                case 0:
+                case 1:
+                        context->frame->action = GDK_PIXBUF_FRAME_RETAIN;
+                        break;
+                case 2:
+                        context->frame->action = GDK_PIXBUF_FRAME_DISPOSE;
+                        break;
+                case 3:
+                        context->frame->action = GDK_PIXBUF_FRAME_REVERT;
+                        break;
+                default:
+                        context->frame->action = GDK_PIXBUF_FRAME_RETAIN;
+                        break;
+                }
+
+                context->frame->bg_transparent = (context->gif89.transparent == context->background_index);
+                
+                {
+                        /* Update animation size */
+                        int w, h;
+                        
+                        context->animation->n_frames ++;
+                        context->animation->frames = g_list_append (context->animation->frames, context->frame);
+
+                        w = context->frame->x_offset +
+                                gdk_pixbuf_get_width (context->frame->pixbuf);
+                        h = context->frame->y_offset +
+                                gdk_pixbuf_get_height (context->frame->pixbuf);
+                        if (w > context->animation->width)
+                                context->animation->width = w;
+                        if (h > context->animation->height)
+                                context->animation->height = h;
+                }
+
+                /* Only call prepare_func for the first frame */
+               if (context->animation->frames->next == NULL) { 
+                        if (context->prepare_func)
+                                (* context->prepare_func) (context->frame->pixbuf,
+                                                           GDK_PIXBUF_ANIMATION (context->animation),
+                                                           context->user_data);
+                } else {
+                        /* Otherwise init frame with last frame */
+                        GList *link;
+                        GdkPixbufFrame *prev_frame;
+                        
+                        link = g_list_find (context->animation->frames, context->frame);
+
+                        prev_frame = link->prev->data;
+
+                        gdk_pixbuf_gif_anim_frame_composite (context->animation, prev_frame);
+
+                        gdk_pixbuf_copy_area (prev_frame->composited,
+                                              context->frame->x_offset,
+                                              context->frame->y_offset,
+                                              gdk_pixbuf_get_width (context->frame->pixbuf),
+                                              gdk_pixbuf_get_height (context->frame->pixbuf),
+                                              context->frame->pixbuf,
+                                              0, 0);
+                }
+        }
+
+       dest = gdk_pixbuf_get_pixels (context->frame->pixbuf);
 
        bound_flag = FALSE;
        lower_bound = upper_bound = context->draw_ypos;
        first_pass = context->draw_pass;
 
        while (TRUE) {
+                guchar (*cmap)[MAXCOLORMAPSIZE];
+
+                if (context->frame_cmap_active)
+                        cmap = context->frame_color_map;
+                else
+                        cmap = context->global_color_map;
+                
                v = lzw_read_byte (context);
                if (v < 0) {
                        goto finished_data;
                }
                bound_flag = TRUE;
 
-               if (context->gif89.transparent != -1) {
-                       temp = dest + context->draw_ypos * gdk_pixbuf_get_rowstride (context->pixbuf) + context->draw_xpos * 4;
-                       *temp = context->color_map [0][(guchar) v];
-                       *(temp+1) = context->color_map [1][(guchar) v];
-                       *(temp+2) = context->color_map [2][(guchar) v];
-                       *(temp+3) = (guchar) ((v == context->gif89.transparent) ? 0 : -1);
-               } else {
-                       temp = dest + context->draw_ypos * gdk_pixbuf_get_rowstride (context->pixbuf) + context->draw_xpos * 3;
-                       *temp = context->color_map [0][(guchar) v];
-                       *(temp+1) = context->color_map [1][(guchar) v];
-                       *(temp+2) = context->color_map [2][(guchar) v];
-               }
+                g_assert (gdk_pixbuf_get_has_alpha (context->frame->pixbuf));
+                
+                temp = dest + context->draw_ypos * gdk_pixbuf_get_rowstride (context->frame->pixbuf) + context->draw_xpos * 4;
+                *temp = cmap [0][(guchar) v];
+                *(temp+1) = cmap [1][(guchar) v];
+                *(temp+2) = cmap [2][(guchar) v];
+                *(temp+3) = (guchar) ((v == context->gif89.transparent) ? 0 : 255);
 
                if (context->prepare_func && context->frame_interlace)
                        gif_fill_in_lines (context, dest, v);
 
                context->draw_xpos++;
-
+                
                if (context->draw_xpos == context->frame_len) {
                        context->draw_xpos = 0;
                        if (context->frame_interlace) {
@@ -796,7 +880,7 @@ gif_get_lzw (GifContext *context)
                                        lower_bound = 0;
                                        upper_bound = context->frame_height;
                                } else {
-
+                                        
                                }
                        } else
                                upper_bound = context->draw_ypos;
@@ -804,56 +888,60 @@ gif_get_lzw (GifContext *context)
                if (context->draw_ypos >= context->frame_height)
                        break;
        }
+
  done:
-       /* we got enough data. there may be more (ie, newer layers) but we can quit now */
-       if (context->animation || context->frame_done_func || context->anim_done_func) {
-               context->state = GIF_GET_NEXT_STEP;
-       } else
-               context->state = GIF_DONE;
-       v = 0;
+
+        context->state = GIF_GET_NEXT_STEP;
+
+        v = 0;
+
  finished_data:
+        
+        if (bound_flag)
+                context->frame->need_recomposite = TRUE;
+        
        if (bound_flag && context->update_func) {
                if (lower_bound <= upper_bound && first_pass == context->draw_pass) {
                        (* context->update_func)
-                               (context->pixbuf,
+                               (context->frame->pixbuf,
                                 0, lower_bound,
-                                gdk_pixbuf_get_width (context->pixbuf),
+                                gdk_pixbuf_get_width (context->frame->pixbuf),
                                 upper_bound - lower_bound,
                                 context->user_data);
                } else {
                        if (lower_bound <= upper_bound) {
                                (* context->update_func)
-                                       (context->pixbuf,
-                                        0, 0,
-                                        gdk_pixbuf_get_width (context->pixbuf),
-                                        gdk_pixbuf_get_height (context->pixbuf),
+                                       (context->frame->pixbuf,
+                                        context->frame->x_offset,
+                                         context->frame->y_offset,
+                                        gdk_pixbuf_get_width (context->frame->pixbuf),
+                                        gdk_pixbuf_get_height (context->frame->pixbuf),
                                         context->user_data);
                        } else {
                                (* context->update_func)
-                                       (context->pixbuf,
-                                        0, 0,
-                                        gdk_pixbuf_get_width (context->pixbuf),
+                                       (context->frame->pixbuf,
+                                        context->frame->x_offset,
+                                         context->frame->y_offset,
+                                        gdk_pixbuf_get_width (context->frame->pixbuf),
                                         upper_bound,
                                         context->user_data);
                                (* context->update_func)
-                                       (context->pixbuf,
-                                        0, lower_bound,
-                                        gdk_pixbuf_get_width (context->pixbuf),
-                                        gdk_pixbuf_get_height (context->pixbuf),
+                                       (context->frame->pixbuf,
+                                        context->frame->x_offset,
+                                         lower_bound + context->frame->y_offset,
+                                        gdk_pixbuf_get_width (context->frame->pixbuf),
+                                        gdk_pixbuf_get_height (context->frame->pixbuf),
                                         context->user_data);
                        }
                }
        }
 
-       if ((context->animation || context->frame_done_func || context->anim_done_func)
-           && context->state == GIF_GET_NEXT_STEP) {
-               if (context->frame_done_func)
-                       (* context->frame_done_func) (context->frame,
-                                                     context->user_data);
-               if (context->frame_done_func)
-                       gdk_pixbuf_unref (context->pixbuf);
-               context->pixbuf = NULL;
+       if (context->state == GIF_GET_NEXT_STEP) {
+                /* Will be freed with context->animation, we are just
+                 * marking that we're done with it (no current frame)
+                 */
                context->frame = NULL;
+                context->frame_cmap_active = FALSE;
        }
        
        return v;
@@ -943,16 +1031,36 @@ gif_init (GifContext *context)
 
        context->width = LM_to_uint (buf[0], buf[1]);
        context->height = LM_to_uint (buf[2], buf[3]);
-       context->bit_pixel = 2 << (buf[4] & 0x07);
-       context->color_resolution = (((buf[4] & 0x70) >> 3) + 1);
-       context->background = buf[5];
+        /* The 4th byte is
+         * high bit: whether to use the background index
+         * next 3:   color resolution
+         * next:     whether colormap is sorted by priority of allocation
+         * last 3:   size of colormap
+         */
+       context->global_bit_pixel = 2 << (buf[4] & 0x07);
+       context->global_color_resolution = (((buf[4] & 0x70) >> 3) + 1);
+        context->has_global_cmap = (buf[4] & 0x80) != 0;
+       context->background_index = buf[5];
        context->aspect_ratio = buf[6];
 
-       if (BitSet (buf[4], LOCALCOLORMAP)) {
+        /* Use background of transparent black as default, though if
+         * one isn't set explicitly no one should ever use it.
+         */
+        context->animation->bg_red = 0;
+        context->animation->bg_green = 0;
+        context->animation->bg_blue = 0;
+        
+       if (context->has_global_cmap) {
                gif_set_get_colormap (context);
        } else {
                context->state = GIF_GET_NEXT_STEP;
        }
+
+#ifdef DUMP_IMAGE_DETAILS
+        g_print (">Image width: %d height: %d global_cmap: %d background: %d\n",
+                 context->width, context->height, context->has_global_cmap, context->background_index);
+#endif
+        
        return 0;
 }
 
@@ -966,38 +1074,81 @@ static gint
 gif_get_frame_info (GifContext *context)
 {
        unsigned char buf[9];
+        
        if (!gif_read (context, buf, 9)) {
                return -1;
        }
+        
        /* Okay, we got all the info we need.  Lets record it */
        context->frame_len = LM_to_uint (buf[4], buf[5]);
        context->frame_height = LM_to_uint (buf[6], buf[7]);
        context->x_offset = LM_to_uint (buf[0], buf[1]);
        context->y_offset = LM_to_uint (buf[2], buf[3]);
 
-       if (context->frame_height > context->height) {
-               /* we don't want to resize things.  So we exit */
+       if (((context->frame_height + context->y_offset) > context->height) ||
+            ((context->frame_len + context->x_offset) > context->width)) {
+               /* All frames must fit in the image bounds */
+               context->state = GIF_DONE;
+
+                g_set_error (context->error,
+                             GDK_PIXBUF_ERROR,
+                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                             _("GIF image contained a frame appearing outside the image bounds."));
+                
+               return -2;
+       }
+        
+       if (context->animation->frames == NULL &&
+            context->gif89.disposal == 3) {
+                /* First frame can't have "revert to previous" as its
+                 * dispose mode.
+                 */
+                
                context->state = GIF_DONE;
 
                 g_set_error (context->error,
                              GDK_PIXBUF_ERROR,
                              GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
-                             _("GIF animation contained a frame with an incorrect size"));
+                             _("First frame of GIF image had 'revert to previous' as its disposal mode."));
                 
                return -2;
        }
 
+#ifdef DUMP_IMAGE_DETAILS
+        g_print (">width: %d height: %d xoffset: %d yoffset: %d disposal: %d delay: %d transparent: %d\n",
+                 context->frame_len, context->frame_height, context->x_offset, context->y_offset,
+                 context->gif89.disposal, context->gif89.delay_time, context->gif89.transparent);
+#endif
+        
        context->frame_interlace = BitSet (buf[8], INTERLACE);
        if (BitSet (buf[8], LOCALCOLORMAP)) {
+
+#ifdef DUMP_IMAGE_DETAILS
+                g_print (">has local colormap\n");
+#endif
+                
                /* Does this frame have it's own colormap. */
                /* really only relevant when looking at the first frame
                 * of an animated gif. */
                /* if it does, we need to re-read in the colormap,
                 * the gray_scale, and the bit_pixel */
-               context->bit_pixel = 1 << ((buf[8] & 0x07) + 1);
+                context->frame_cmap_active = TRUE;
+               context->frame_bit_pixel = 1 << ((buf[8] & 0x07) + 1);
                gif_set_get_colormap2 (context);
                return 0;
        }
+
+        if (!context->has_global_cmap) {
+                context->state = GIF_DONE;
+                
+                g_set_error (context->error,
+                             GDK_PIXBUF_ERROR,
+                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                             _("GIF image has no global colormap, and a frame inside it has no local colormap."));
+                
+               return -2;
+        }
+
        gif_set_prepare_lzw (context);
        return 0;
 
@@ -1037,6 +1188,8 @@ gif_get_next_step (GifContext *context)
 }
 
 
+#define LOG(x)
+
 static gint
 gif_main_loop (GifContext *context)
 {
@@ -1045,52 +1198,63 @@ gif_main_loop (GifContext *context)
        do {
                switch (context->state) {
                case GIF_START:
+                        LOG("start\n");
                        retval = gif_init (context);
                        break;
 
                case GIF_GET_COLORMAP:
+                        LOG("get_colormap\n");
                        retval = gif_get_colormap (context);
                        if (retval == 0)
                                context->state = GIF_GET_NEXT_STEP;
                        break;
 
                case GIF_GET_NEXT_STEP:
+                        LOG("next_step\n");
                        retval = gif_get_next_step (context);
                        break;
 
                case GIF_GET_FRAME_INFO:
+                        LOG("frame_info\n");
                        retval = gif_get_frame_info (context);
                        break;
 
                case GIF_GET_EXTENTION:
+                        LOG("get_extension\n");
                        retval = gif_get_extension (context);
                        if (retval == 0)
                                context->state = GIF_GET_NEXT_STEP;
                        break;
 
                case GIF_GET_COLORMAP2:
-                       retval = gif_get_colormap (context);
+                        LOG("get_colormap2\n");
+                       retval = gif_get_colormap2 (context);
                        if (retval == 0)
                                gif_set_prepare_lzw (context);
                        break;
 
                case GIF_PREPARE_LZW:
+                        LOG("prepare_lzw\n");
                        retval = gif_prepare_lzw (context);
                        break;
 
                case GIF_LZW_FILL_BUFFER:
+                        LOG("fill_buffer\n");
                        retval = gif_lzw_fill_buffer (context);
                        break;
 
                case GIF_LZW_CLEAR_CODE:
+                        LOG("clear_code\n");
                        retval = gif_lzw_clear_code (context);
                        break;
 
                case GIF_GET_LZW:
+                        LOG("get_lzw\n");
                        retval = gif_get_lzw (context);
                        break;
 
                case GIF_DONE:
+                        LOG("done\n");
                default:
                        retval = 0;
                        goto done;
@@ -1107,13 +1271,12 @@ new_context (void)
 
        context = g_new0 (GifContext, 1);
 
-       context->pixbuf = NULL;
+        context->animation = g_object_new (GDK_TYPE_PIXBUF_GIF_ANIM, NULL);        
+       context->frame = NULL;
        context->file = NULL;
        context->state = GIF_START;
        context->prepare_func = NULL;
        context->update_func = NULL;
-       context->frame_done_func = NULL;
-       context->anim_done_func = NULL;
        context->user_data = NULL;
        context->buf = NULL;
        context->amount_needed = 0;
@@ -1137,9 +1300,22 @@ gdk_pixbuf__gif_image_load (FILE *file, GError **error)
        context->file = file;
         context->error = error;
         
-       gif_main_loop (context);
+       if (gif_main_loop (context) == -1 || context->animation->frames == NULL) {
+                if (context->error && *(context->error) == NULL)
+                        g_set_error (context->error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                     _("GIF file was missing some data (perhaps it was truncated somehow?)"));
+        }
+        
+        pixbuf = gdk_pixbuf_animation_get_static_image (GDK_PIXBUF_ANIMATION (context->animation));
 
-       pixbuf = context->pixbuf;
+        if (pixbuf)
+                g_object_ref (G_OBJECT (pixbuf));
+
+        g_object_unref (G_OBJECT (context->animation));
+        
+        g_free (context->buf);
        g_free (context);
  
        return pixbuf;
@@ -1148,8 +1324,6 @@ gdk_pixbuf__gif_image_load (FILE *file, GError **error)
 static gpointer
 gdk_pixbuf__gif_image_begin_load (ModulePreparedNotifyFunc prepare_func,
                                  ModuleUpdatedNotifyFunc update_func,
-                                 ModuleFrameDoneNotifyFunc frame_done_func,
-                                 ModuleAnimationDoneNotifyFunc anim_done_func,
                                  gpointer user_data,
                                   GError **error)
 {
@@ -1162,8 +1336,6 @@ gdk_pixbuf__gif_image_begin_load (ModulePreparedNotifyFunc prepare_func,
         context->error = error;
        context->prepare_func = prepare_func;
        context->update_func = update_func;
-       context->frame_done_func = frame_done_func;
-       context->anim_done_func = anim_done_func;
        context->user_data = user_data;
 
        return (gpointer) context;
@@ -1173,21 +1345,23 @@ static gboolean
 gdk_pixbuf__gif_image_stop_load (gpointer data, GError **error)
 {
        GifContext *context = (GifContext *) data;
-
-       /* FIXME: free the animation data */
+        gboolean retval = TRUE;
         
-        /* FIXME this thing needs to report errors if
-         * we have unused image data
-         */
+        if (context->state != GIF_DONE) {
+                g_set_error (error,
+                             GDK_PIXBUF_ERROR,
+                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                             _("GIF image was truncated or incomplete."));
+
+                retval = FALSE;
+        }
         
-       if (context->pixbuf)
-               gdk_pixbuf_unref (context->pixbuf);
-       if (context->animation)
-               gdk_pixbuf_animation_unref (context->animation);
-/*     g_free (context->buf);*/
+        g_object_unref (G_OBJECT (context->animation));
+
+       g_free (context->buf);
        g_free (context);
 
-        return TRUE;
+        return retval;
 }
 
 static gboolean
@@ -1264,18 +1438,28 @@ gdk_pixbuf__gif_image_load_animation (FILE *file,
        context = new_context ();
 
         context->error = error;
-        
-       context->animation = g_object_new (GDK_TYPE_PIXBUF_ANIMATION, NULL);
-
-       context->animation->n_frames = 0;
-       context->animation->frames = NULL;
-       context->animation->width = 0;
-       context->animation->height = 0;
        context->file = file;
 
-       gif_main_loop (context);
+       if (gif_main_loop (context) == -1 || context->animation->frames == NULL) {
+                if (context->error && *(context->error) == NULL)
+                        g_set_error (context->error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                     _("GIF file was missing some data (perhaps it was truncated somehow?)"));
 
-       animation = context->animation;
+                g_object_unref (G_OBJECT (context->animation));
+                context->animation = NULL;
+        }
+
+        if (context->animation)
+                animation = GDK_PIXBUF_ANIMATION (context->animation);
+        else
+                animation = NULL;
+
+        if (context->error && *(context->error))
+                g_print ("%s\n", (*(context->error))->message);
+        
+        g_free (context->buf);
        g_free (context);
        return animation;
 }
index dc6dadb2f877c5a9dbd6c0e01436ac445d574cd7..6a2ca4884077ca481699e0e4d06d5c5bd14963a3 100644 (file)
@@ -156,8 +156,6 @@ struct ico_progressive_state {
 static gpointer
 gdk_pixbuf__ico_image_begin_load(ModulePreparedNotifyFunc prepared_func,
                                 ModuleUpdatedNotifyFunc updated_func,
-                                ModuleFrameDoneNotifyFunc frame_done_func,
-                                ModuleAnimationDoneNotifyFunc anim_done_func,
                                 gpointer user_data,
                                  GError **error);
 static gboolean gdk_pixbuf__ico_image_stop_load(gpointer data, GError **error);
@@ -178,8 +176,8 @@ gdk_pixbuf__ico_image_load(FILE * f, GError **error)
 
        GdkPixbuf *pb;
 
-       State = gdk_pixbuf__ico_image_begin_load(NULL, NULL, NULL,
-                                                 NULL, NULL, error);
+       State = gdk_pixbuf__ico_image_begin_load(NULL, NULL, NULL, error);
+
         if (State == NULL)
           return NULL;
         
@@ -363,6 +361,7 @@ static void DecodeHeader(guchar *Data, gint Bytes,
                if (State->prepared_func != NULL)
                        /* Notify the client that we are ready to go */
                        (*State->prepared_func) (State->pixbuf,
+                                                 NULL,
                                                 State->user_data);
 
        }
@@ -378,8 +377,6 @@ static void DecodeHeader(guchar *Data, gint Bytes,
 static gpointer
 gdk_pixbuf__ico_image_begin_load(ModulePreparedNotifyFunc prepared_func,
                                 ModuleUpdatedNotifyFunc updated_func,
-                                ModuleFrameDoneNotifyFunc frame_done_func,
-                                ModuleAnimationDoneNotifyFunc anim_done_func,
                                 gpointer user_data,
                                  GError **error)
 {
index 2c295131d98a7af916d39f13e345a5ca6f679f93..c707d347af6867869a5c05eab66521ea45c96544 100644 (file)
@@ -96,8 +96,6 @@ typedef struct {
 static GdkPixbuf *gdk_pixbuf__jpeg_image_load (FILE *f, GError **error);
 static gpointer gdk_pixbuf__jpeg_image_begin_load (ModulePreparedNotifyFunc func, 
                                                    ModuleUpdatedNotifyFunc func2,
-                                                   ModuleFrameDoneNotifyFunc func3,
-                                                   ModuleAnimationDoneNotifyFunc func4,
                                                    gpointer user_data,
                                                    GError **error);
 static gboolean gdk_pixbuf__jpeg_image_stop_load (gpointer context, GError **error);
@@ -321,8 +319,6 @@ skip_input_data (j_decompress_ptr cinfo, long num_bytes)
 gpointer
 gdk_pixbuf__jpeg_image_begin_load (ModulePreparedNotifyFunc prepared_func, 
                                   ModuleUpdatedNotifyFunc  updated_func,
-                                  ModuleFrameDoneNotifyFunc frame_func,
-                                  ModuleAnimationDoneNotifyFunc anim_done_func,
                                   gpointer user_data,
                                    GError **error)
 {
@@ -539,6 +535,7 @@ gdk_pixbuf__jpeg_image_load_increment (gpointer data,
 
                        /* Notify the client that we are ready to go */
                        (* context->prepared_func) (context->pixbuf,
+                                                    NULL,
                                                    context->user_data);
 
                } else if (!context->did_prescan) {
index 9ece35d40dfae9f55bbd1df0a1e3444016c271e5..21b1d4b296572fee586424061f10d1a9690fca9e 100644 (file)
@@ -324,8 +324,6 @@ struct _LoadContext {
 static gpointer
 gdk_pixbuf__png_image_begin_load (ModulePreparedNotifyFunc prepare_func,
                                  ModuleUpdatedNotifyFunc update_func,
-                                 ModuleFrameDoneNotifyFunc frame_done_func,
-                                 ModuleAnimationDoneNotifyFunc anim_done_func,
                                  gpointer user_data,
                                   GError **error)
 {
@@ -540,7 +538,7 @@ png_info_callback   (png_structp png_read_ptr,
         /* Notify the client that we are ready to go */
 
         if (lc->prepare_func)
-                (* lc->prepare_func) (lc->pixbuf, lc->notify_user_data);
+                (* lc->prepare_func) (lc->pixbuf, NULL, lc->notify_user_data);
         
         return;
 }
index 87c392db5a44bf737422bb1e0f018843a592b6ac..cd7dd9d9bdb0217f309891a0697e639fb58d9564 100644 (file)
@@ -84,8 +84,6 @@ typedef struct {
 static GdkPixbuf   *gdk_pixbuf__pnm_image_load          (FILE *f, GError **error);
 static gpointer    gdk_pixbuf__pnm_image_begin_load     (ModulePreparedNotifyFunc func, 
                                                         ModuleUpdatedNotifyFunc func2,
-                                                        ModuleFrameDoneNotifyFunc frame_done_func,
-                                                        ModuleAnimationDoneNotifyFunc anim_done_func,
                                                         gpointer user_data,
                                                         GError **error);
 static gboolean    gdk_pixbuf__pnm_image_stop_load      (gpointer context, GError **error);
@@ -763,8 +761,6 @@ gdk_pixbuf__pnm_image_load (FILE *f, GError **error)
 static gpointer
 gdk_pixbuf__pnm_image_begin_load (ModulePreparedNotifyFunc prepared_func, 
                                  ModuleUpdatedNotifyFunc  updated_func,
-                                 ModuleFrameDoneNotifyFunc frame_done_func,
-                                 ModuleAnimationDoneNotifyFunc anim_done_func,
                                  gpointer user_data,
                                  GError **error)
 {
@@ -923,6 +919,7 @@ gdk_pixbuf__pnm_image_load_increment (gpointer data,
                        
                        /* Notify the client that we are ready to go */
                        (* context->prepared_func) (context->pixbuf,
+                                                   NULL,
                                                    context->user_data);
                }
                
index 25a3c0b7a5b6f8c20d94ba1954666ef5c20f0456..84b7c27f9282e28a0bffac5730c97a23cd44fb4d 100644 (file)
@@ -96,8 +96,6 @@ struct ras_progressive_state {
 static gpointer
 gdk_pixbuf__ras_image_begin_load(ModulePreparedNotifyFunc prepared_func,
                                 ModuleUpdatedNotifyFunc updated_func,
-                                ModuleFrameDoneNotifyFunc frame_done_func,
-                                ModuleAnimationDoneNotifyFunc anim_done_func,
                                 gpointer user_data,
                                  GError **error);
 static gboolean gdk_pixbuf__ras_image_stop_load(gpointer data, GError **error);
@@ -116,8 +114,7 @@ static GdkPixbuf *gdk_pixbuf__ras_image_load(FILE * f, GError **error)
        
        GdkPixbuf *pb;
        
-       State = gdk_pixbuf__ras_image_begin_load(NULL, NULL, NULL,
-                                                 NULL, NULL, error);
+       State = gdk_pixbuf__ras_image_begin_load(NULL, NULL, NULL, error);
        
        membuf = g_malloc(4096);
        
@@ -195,6 +192,7 @@ static void RAS2State(struct rasterfile *RAS,
                if (State->prepared_func != NULL)
                        /* Notify the client that we are ready to go */
                        (*State->prepared_func) (State->pixbuf,
+                                                 NULL,
                                                 State->user_data);
 
        }
@@ -219,8 +217,6 @@ static void RAS2State(struct rasterfile *RAS,
 static gpointer
 gdk_pixbuf__ras_image_begin_load(ModulePreparedNotifyFunc prepared_func,
                                 ModuleUpdatedNotifyFunc updated_func,
-                                ModuleFrameDoneNotifyFunc frame_done_func,
-                                ModuleAnimationDoneNotifyFunc anim_done_func,
                                 gpointer user_data,
                                  GError **error)
 {
index 9b23f5d719442364413a4f92bd607e00435d9c3a..51040dcdada93af9fbb73ff7cf29e60686f0a65b 100644 (file)
@@ -92,7 +92,7 @@ gdk_pixbuf__tiff_image_load_real (FILE *f, TiffData *context, GError **error)
         }
         
        if (context)
-               (* context->prepare_func) (pixbuf, context->user_data);
+               (* context->prepare_func) (pixbuf, NULL, context->user_data);
 
        /* Yes, it needs to be _TIFFMalloc... */
        rast = (uint32 *) _TIFFmalloc (num_pixs * sizeof (uint32));
@@ -163,8 +163,6 @@ gdk_pixbuf__tiff_image_load (FILE *f, GError **error)
 static gpointer
 gdk_pixbuf__tiff_image_begin_load (ModulePreparedNotifyFunc prepare_func,
                                   ModuleUpdatedNotifyFunc update_func,
-                                  ModuleFrameDoneNotifyFunc frame_done_func,
-                                  ModuleAnimationDoneNotifyFunc anim_done_func,
                                   gpointer user_data,
                                    GError **error)
 {
index 1b7784b13d81c08929432248c78b1e65a8575b45..1537d83d624eb36b8a5c7fc0fc4a47e7bb32f755 100644 (file)
@@ -65,9 +65,7 @@ struct wbmp_progressive_state {
 static gpointer
 gdk_pixbuf__wbmp_image_begin_load(ModulePreparedNotifyFunc prepared_func,
                                  ModuleUpdatedNotifyFunc updated_func,
-                                 ModuleFrameDoneNotifyFunc frame_done_func,
-                                 ModuleAnimationDoneNotifyFunc
-                                 anim_done_func, gpointer user_data,
+                                  gpointer user_data,
                                   GError **error);
 
 static gboolean gdk_pixbuf__wbmp_image_stop_load(gpointer data, GError **error);
@@ -87,7 +85,7 @@ static GdkPixbuf *gdk_pixbuf__wbmp_image_load(FILE * f, GError **error)
 
        GdkPixbuf *pb;
 
-       State = gdk_pixbuf__wbmp_image_begin_load(NULL, NULL, NULL, NULL, NULL,
+       State = gdk_pixbuf__wbmp_image_begin_load(NULL, NULL, NULL,
                                                   error);
 
         if (State == NULL)
@@ -120,9 +118,7 @@ static GdkPixbuf *gdk_pixbuf__wbmp_image_load(FILE * f, GError **error)
 static gpointer
 gdk_pixbuf__wbmp_image_begin_load(ModulePreparedNotifyFunc prepared_func,
                                   ModuleUpdatedNotifyFunc updated_func,
-                                  ModuleFrameDoneNotifyFunc frame_done_func,
-                                  ModuleAnimationDoneNotifyFunc
-                                  anim_done_func, gpointer user_data,
+                                  gpointer user_data,
                                   GError **error)
 {
        struct wbmp_progressive_state *context;
@@ -285,7 +281,7 @@ static gboolean gdk_pixbuf__wbmp_image_load_increment(gpointer data,
                    g_assert(context->pixbuf);
 
                    if(context->prepared_func)
-                     context->prepared_func(context->pixbuf, context->user_data);
+                     context->prepared_func(context->pixbuf, NULL, context->user_data);
                  }
              }
            else if(context->needmore)
index 05d8f994a49a4421d293d6b76eaee2eec00bccfb..0041488eb8175e3499d46ddd17414620fc565d71 100644 (file)
@@ -300,7 +300,7 @@ gdk_pixbuf__xbm_image_load_real (FILE *f, XBMData *context, GError **error)
        row_stride = gdk_pixbuf_get_rowstride (pixbuf);
 
        if (context)
-               (* context->prepare_func) (pixbuf, context->user_data);
+               (* context->prepare_func) (pixbuf, NULL, context->user_data);
 
 
        /* Initialize PIXBUF */
@@ -355,8 +355,6 @@ gdk_pixbuf__xbm_image_load (FILE *f, GError **error)
 static gpointer
 gdk_pixbuf__xbm_image_begin_load (ModulePreparedNotifyFunc prepare_func,
                                  ModuleUpdatedNotifyFunc update_func,
-                                 ModuleFrameDoneNotifyFunc frame_done_func,
-                                 ModuleAnimationDoneNotifyFunc anim_done_func,
                                  gpointer user_data,
                                  GError **error)
 {
index 0ddc3c234e4cb366ac48ca802e870fde5c4cf281..1f99088c3d46e5d5983f8402da1e8aac07e902a9 100644 (file)
@@ -1424,8 +1424,6 @@ struct _XPMContext
 static gpointer
 gdk_pixbuf__xpm_image_begin_load (ModulePreparedNotifyFunc prepare_func,
                                   ModuleUpdatedNotifyFunc update_func,
-                                  ModuleFrameDoneNotifyFunc frame_done_func,
-                                  ModuleAnimationDoneNotifyFunc anim_done_func,
                                   gpointer user_data,
                                   GError **error)
 {
@@ -1471,7 +1469,9 @@ gdk_pixbuf__xpm_image_stop_load (gpointer data,
                pixbuf = gdk_pixbuf__xpm_image_load (context->file, error);
 
                if (pixbuf != NULL) {
-                       (* context->prepare_func) (pixbuf, context->user_data);
+                       (* context->prepare_func) (pixbuf,
+                                                  NULL,
+                                                  context->user_data);
                        (* context->update_func) (pixbuf, 0, 0, pixbuf->width, pixbuf->height, context->user_data);
                        gdk_pixbuf_unref (pixbuf);
 
index ea19607153f0299061d11907fdbdb5ef7133e6af..7a13e043baec1faf213bd1b915f828d35c8d568c 100644 (file)
@@ -1,4 +1,5 @@
 #include <math.h>
+#include <glib.h>
 #include "config.h"
 
 #include "pixops.h"
@@ -93,6 +94,7 @@ pixops_scale_nearest (guchar        *dest_buf,
   for (i = 0; i < (render_y1 - render_y0); i++)
     {
       const guchar *src  = src_buf + (((i + render_y0) * y_step + y_step / 2) >> SCALE_SHIFT) * src_rowstride;
+      /* FIXME Owen needs to look at this */
       guchar       *dest = dest_buf + i * dest_rowstride;
 
       x = render_x0 * x_step + x_step / 2;
@@ -160,7 +162,6 @@ pixops_composite_nearest (guchar        *dest_buf,
   for (i = 0; i < (render_y1 - render_y0); i++)
     {
       const guchar *src  = src_buf + (((i + render_y0) * y_step + y_step / 2) >> SCALE_SHIFT) * src_rowstride;
-      /* FIXME Owen needs to look at this */
       guchar       *dest = dest_buf + i * dest_rowstride;
 
       x = render_x0 * x_step + x_step / 2;
@@ -183,9 +184,9 @@ pixops_composite_nearest (guchar        *dest_buf,
 
              if (w != 0)
                {
-                 dest[0] = (w0 * src[0] + w1 * dest[0]) / w;
-                 dest[1] = (w0 * src[1] + w1 * dest[1]) / w;
-                 dest[2] = (w0 * src[2] + w1 * dest[2]) / w;
+                 dest[0] = (w0 * p[0] + w1 * dest[0]) / w;
+                 dest[1] = (w0 * p[1] + w1 * dest[1]) / w;
+                 dest[2] = (w0 * p[2] + w1 * dest[2]) / w;
                  dest[3] = w / 0xff;
                }
              else
@@ -274,25 +275,39 @@ pixops_composite_color_nearest (guchar        *dest_buf,
       for (j=0 ; j < (render_x1 - render_x0); j++)
        {
          const guchar *p = src + (x >> SCALE_SHIFT) * src_channels;
-          unsigned int  a0;
+          int a0;
+         int tmp;
 
          if (src_has_alpha)
            a0 = (p[3] * overall_alpha + 0xff) >> 8;
          else
            a0 = overall_alpha;
 
-         if (((j + check_x) >> check_shift) & 1)
+         if (a0 == 255)
            {
-             dest[0] = r2 + ((a0 * ((int)p[0] - r2) + 0xff) >> 8);
-             dest[1] = g2 + ((a0 * ((int)p[1] - g2) + 0xff) >> 8);
-             dest[2] = b2 + ((a0 * ((int)p[2] - b2) + 0xff) >> 8);
+             dest[0] = p[0];
+             dest[1] = p[1];
+             dest[2] = p[2];
            }
          else
-           {
-             dest[0] = r1 + ((a0 * ((int)p[0] - r1) + 0xff) >> 8);
-             dest[1] = g1 + ((a0 * ((int)p[1] - g1) + 0xff) >> 8);
-             dest[2] = b1 + ((a0 * ((int)p[2] - b1) + 0xff) >> 8);
-           }
+           if (((j + check_x) >> check_shift) & 1)
+             {
+               tmp = ((int) p[0] - r2) * a0;
+               dest[0] = r2 + ((tmp + (tmp >> 8) + 0x80) >> 8);
+               tmp = ((int) p[1] - g2) * a0;
+               dest[1] = g2 + ((tmp + (tmp >> 8) + 0x80) >> 8);
+               tmp = ((int) p[2] - b2) * a0;
+               dest[2] = b2 + ((tmp + (tmp >> 8) + 0x80) >> 8);
+             }
+           else
+             {
+               tmp = ((int) p[0] - r1) * a0;
+               dest[0] = r1 + ((tmp + (tmp >> 8) + 0x80) >> 8);
+               tmp = ((int) p[1] - g1) * a0;
+               dest[1] = g1 + ((tmp + (tmp >> 8) + 0x80) >> 8);
+               tmp = ((int) p[2] - b1) * a0;
+               dest[2] = b1 + ((tmp + (tmp >> 8) + 0x80) >> 8);
+             }
          
          if (dest_channels == 4)
            dest[3] = 0xff;
@@ -1003,7 +1018,7 @@ pixops_process (guchar         *dest_buf,
 
       dest_x += (new_outbuf - outbuf) / dest_channels;
 
-      x = dest_x * x_step + scaled_x_offset;
+      x = (dest_x - check_x + render_x0) * x_step + scaled_x_offset;
       outbuf = new_outbuf;
 
       while (outbuf < outbuf_end)
index 9a6f65cbfd1d2cd3a4c54ed26e7428d3dfaefe9d..706fffd2c36d339125df519d362032eff2de2b82 100644 (file)
@@ -70,6 +70,7 @@ enum {
   PROP_STRETCH,
   PROP_SIZE,
   PROP_SIZE_POINTS,
+  PROP_SCALE,
   PROP_EDITABLE,
   PROP_STRIKETHROUGH,
   PROP_UNDERLINE,
@@ -84,6 +85,7 @@ enum {
   PROP_WEIGHT_SET,
   PROP_STRETCH_SET,
   PROP_SIZE_SET,
+  PROP_SCALE_SET,
   PROP_EDITABLE_SET,
   PROP_STRIKETHROUGH_SET,
   PROP_UNDERLINE_SET,
@@ -282,6 +284,16 @@ gtk_cell_renderer_text_class_init (GtkCellRendererTextClass *class)
                                                         G_MAXDOUBLE,
                                                         0.0,
                                                         G_PARAM_READABLE | G_PARAM_WRITABLE));  
+
+  g_object_class_install_property (object_class,
+                                   PROP_SCALE,
+                                   g_param_spec_double ("scale",
+                                                        _("Font scale"),
+                                                        _("Font scaling factor"),
+                                                        0.0,
+                                                        G_MAXDOUBLE,
+                                                        1.0,
+                                                        G_PARAM_READABLE | G_PARAM_WRITABLE));
   
   g_object_class_install_property (object_class,
                                    PROP_RISE,
@@ -351,6 +363,10 @@ gtk_cell_renderer_text_class_init (GtkCellRendererTextClass *class)
                 _("Font size set"),
                 _("Whether this tag affects the font size"));
 
+  ADD_SET_PROP ("scale_set", PROP_SCALE_SET,
+                _("Font scale set"),
+                _("Whether this tag scales the font size by a factor"));
+  
   ADD_SET_PROP ("rise_set", PROP_RISE_SET,
                 _("Rise set"),
                 _("Whether this tag affects the rise"));
@@ -462,6 +478,10 @@ gtk_cell_renderer_text_get_property (GObject        *object,
       g_value_set_double (value, ((double)celltext->font.size) / (double)PANGO_SCALE);
       break;
 
+    case PROP_SCALE:
+      g_value_set_double (value, celltext->font_scale);
+      break;
+      
     case PROP_EDITABLE:
       g_value_set_boolean (value, celltext->editable);
       break;
@@ -510,6 +530,10 @@ gtk_cell_renderer_text_get_property (GObject        *object,
       g_value_set_boolean (value, celltext->size_set);
       break;
 
+    case PROP_SCALE_SET:
+      g_value_set_boolean (value, celltext->scale_set);
+      break;
+      
     case PROP_EDITABLE_SET:
       g_value_set_boolean (value, celltext->editable_set);
       break;
@@ -824,6 +848,11 @@ gtk_cell_renderer_text_set_property (GObject      *object,
       g_object_notify (G_OBJECT (celltext), "font");
       break;
 
+    case PROP_SCALE:
+      celltext->font_scale = g_value_get_double (value);
+      celltext->scale_set = TRUE;
+      break;
+      
     case PROP_SIZE_POINTS:
       celltext->font.size = g_value_get_double (value) * PANGO_SCALE;
 
@@ -849,6 +878,7 @@ gtk_cell_renderer_text_set_property (GObject      *object,
       celltext->underline_style = g_value_get_enum (value);
       celltext->underline_set = TRUE;
       g_object_notify (G_OBJECT (celltext), "underline_set");
+            
       break;
 
     case PROP_RISE:
@@ -859,62 +889,54 @@ gtk_cell_renderer_text_set_property (GObject      *object,
 
     case PROP_BACKGROUND_SET:
       celltext->background_set = g_value_get_boolean (value);
-      g_object_notify(G_OBJECT(object), "background_set");
       break;
 
     case PROP_FOREGROUND_SET:
       celltext->foreground_set = g_value_get_boolean (value);
-      g_object_notify(G_OBJECT(object), "foreground_set");
       break;
 
     case PROP_FAMILY_SET:
       celltext->family_set = g_value_get_boolean (value);
-      g_object_notify(G_OBJECT(object), "family_set");
       break;
 
     case PROP_STYLE_SET:
       celltext->style_set = g_value_get_boolean (value);
-      g_object_notify(G_OBJECT(object), "style_set");
       break;
 
     case PROP_VARIANT_SET:
       celltext->variant_set = g_value_get_boolean (value);
-      g_object_notify(G_OBJECT(object), "variant_set");
       break;
 
     case PROP_WEIGHT_SET:
       celltext->weight_set = g_value_get_boolean (value);
-      g_object_notify(G_OBJECT(object), "weight_set");
       break;
 
     case PROP_STRETCH_SET:
       celltext->stretch_set = g_value_get_boolean (value);
-      g_object_notify(G_OBJECT(object), "stretch_set");
       break;
 
     case PROP_SIZE_SET:
       celltext->size_set = g_value_get_boolean (value);
-      g_object_notify(G_OBJECT(object), "size_set");
       break;
 
+    case PROP_SCALE_SET:
+      celltext->scale_set = g_value_get_boolean (value);
+      break;
+      
     case PROP_EDITABLE_SET:
       celltext->editable_set = g_value_get_boolean (value);
-      g_object_notify(G_OBJECT(object), "editable_set");
       break;
 
     case PROP_STRIKETHROUGH_SET:
       celltext->strikethrough_set = g_value_get_boolean (value);
-      g_object_notify(G_OBJECT(object), "strikethrough_set");
       break;
 
     case PROP_UNDERLINE_SET:
       celltext->underline_set = g_value_get_boolean (value);
-      g_object_notify(G_OBJECT(object), "underline_set");
       break;
 
     case PROP_RISE_SET:
       celltext->rise_set = g_value_get_boolean (value);
-      g_object_notify(G_OBJECT(object), "rise_set");
       break;
 
     default:
@@ -1012,6 +1034,10 @@ get_layout (GtkCellRendererText *celltext,
       celltext->font.size >= 0)
     add_attr (attr_list, pango_attr_size_new (celltext->font.size));
 
+  if (celltext->scale_set &&
+      celltext->font_scale != 1.0)
+    add_attr (attr_list, pango_attr_scale_new (celltext->font_scale));
+  
   if (celltext->underline_set)
     uline = celltext->underline_style;
   else
index fd906a3350a0bff6a5e6180661ddc49f347da235..3ec185228885cd12a4a0d447571b3d0cc0b5c2c6 100644 (file)
@@ -44,6 +44,7 @@ struct _GtkCellRendererText
   /*< private >*/
   gchar *text;
   PangoFontDescription font;
+  gdouble font_scale;
   PangoColor foreground;
   PangoColor background;
   
@@ -66,6 +67,8 @@ struct _GtkCellRendererText
   guint stretch_set : 1;
   guint size_set : 1;
 
+  guint scale_set : 1;
+  
   guint foreground_set : 1;
   guint background_set : 1;
   
index 802b85e017f78f7793bd1a6732b2870aa79ba435..f888e651137d4aa46de9a7c5c8ef911e7fc0785d 100644 (file)
@@ -246,8 +246,8 @@ gtk_check_button_size_request (GtkWidget      *widget,
       gint indicator_spacing;
       gint border_width = GTK_CONTAINER (widget)->border_width;
       
-      requisition->width = border_width + 2;
-      requisition->height = border_width + 2;
+      requisition->width = border_width * 2 + 2;
+      requisition->height = border_width * 2 + 2;
 
       child = GTK_BIN (widget)->child;
       if (child && GTK_WIDGET_VISIBLE (child))
@@ -255,7 +255,7 @@ gtk_check_button_size_request (GtkWidget      *widget,
          GtkRequisition child_requisition;
          
          gtk_widget_size_request (child, &child_requisition);
-         
+
          requisition->width += child_requisition.width;
          requisition->height += child_requisition.height;
        }
index a894e9fc5cf6b2ff3626b0b60ccee7933abba1f3..4f1e61ac4fe941efe47158d3c7e1b9ef99ca366b 100644 (file)
@@ -1848,7 +1848,7 @@ gtk_color_selection_destroy (GtkObject *object)
 
   if (priv->tooltips)
     {
-      gtk_object_destroy (priv->tooltips);
+      gtk_object_destroy (GTK_OBJECT (priv->tooltips));
       priv->tooltips = NULL;
     }
   
index 0fa644b68ae680bde95bfbfd5d12e210f6179e4c..29f6321fbfe16536e7572f9b76174be802c3f889 100644 (file)
@@ -523,7 +523,6 @@ gtk_hscale_draw_value (GtkScale *scale)
 {
   GtkStateType state_type;
   GtkWidget *widget;
-  gchar buffer[32];
   gint width, height;
   gint x, y;
   
@@ -536,9 +535,14 @@ gtk_hscale_draw_value (GtkScale *scale)
     {
       PangoLayout *layout;
       PangoRectangle logical_rect;
+      gchar *txt;
+
+      txt = _gtk_scale_format_value (scale,
+                                     GTK_RANGE (scale)->adjustment->value);
+      
+      layout = gtk_widget_create_pango_layout (widget, txt);
+      g_free (txt);
       
-      sprintf (buffer, "%0.*f", GTK_RANGE (scale)->digits, GTK_RANGE (scale)->adjustment->value);
-      layout = gtk_widget_create_pango_layout (widget, buffer);
       pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
 
       switch (scale->value_pos)
index 81f0debc188ceed40ef69e3b06b255466533f1a4..e5890a16c46684c0e404b6b396b486a1cfdb3925 100644 (file)
 #include "gtkimage.h"
 #include "gtkiconfactory.h"
 #include "gtkstock.h"
+#include <string.h>
 
 static void gtk_image_class_init   (GtkImageClass  *klass);
 static void gtk_image_init         (GtkImage       *image);
 static gint gtk_image_expose       (GtkWidget      *widget,
                                     GdkEventExpose *event);
+static void gtk_image_unmap        (GtkWidget      *widget);
 static void gtk_image_size_request (GtkWidget      *widget,
                                     GtkRequisition *requisition);
 static void gtk_image_destroy      (GtkObject      *object);
@@ -85,6 +87,7 @@ gtk_image_class_init (GtkImageClass *class)
 
   widget_class->expose_event = gtk_image_expose;
   widget_class->size_request = gtk_image_size_request;
+  widget_class->unmap = gtk_image_unmap;
 }
 
 static void
@@ -163,11 +166,22 @@ gtk_image_new_from_image  (GdkImage  *gdk_image,
  * gtk_image_new_from_file:
  * @filename: a filename
  * 
- * Creates a new #GtkImage displaying the file @filename. If the
- * file isn't found or can't be loaded, the #GtkImage will display
- * a "broken image" icon. If you need to detect failures to load
- * the file, use gdk_pixbuf_new_from_file() to load the file yourself,
- * then create the #GtkImage from the pixbuf.
+ * Creates a new #GtkImage displaying the file @filename. If the file
+ * isn't found or can't be loaded, the resulting #GtkImage will
+ * display a "broken image" icon. This function never returns %NULL,
+ * it always returns a valid #GtkImage widget.
+ *
+ * If the file contains an animation, the image will contain an
+ * animation.
+ *
+ * If you need to detect failures to load the file, use
+ * gdk_pixbuf_new_from_file() to load the file yourself, then create
+ * the #GtkImage from the pixbuf. (Or for animations, use
+ * gdk_pixbuf_animation_new_from_file()).
+ *
+ * The storage type (gtk_image_get_storage_type()) of the returned
+ * image is not defined, it will be whatever is appropriate for
+ * displaying the file.
  * 
  * Return value: a new #GtkImage
  **/
@@ -194,7 +208,7 @@ gtk_image_new_from_file   (const gchar *filename)
  * 
  * Note that this function just creates an #GtkImage from the pixbuf.  The
  * #GtkImage created will not react to state changes.  Should you want that, you
- * should use @gtk_image_new_from_icon_set.
+ * should use gtk_image_new_from_icon_set().
  * 
  * Return value: a new #GtkImage
  **/
@@ -268,6 +282,31 @@ gtk_image_new_from_icon_set (GtkIconSet     *icon_set,
   return GTK_WIDGET (image);
 }
 
+/**
+ * gtk_image_new_from_animation:
+ * @animation: an animation
+ * 
+ * Creates a #GtkImage displaying the given animation.
+ * The #GtkImage does not assume a reference to the
+ * animation; you still need to unref it if you own references.
+ * #GtkImage will add its own reference rather than adopting yours.
+ * 
+ * Return value: a new #GtkImage widget
+ **/
+GtkWidget*
+gtk_image_new_from_animation (GdkPixbufAnimation *animation)
+{
+  GtkImage *image;
+
+  g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION (animation), NULL);
+  
+  image = gtk_type_new (GTK_TYPE_IMAGE);
+
+  gtk_image_set_from_animation (image, animation);
+
+  return GTK_WIDGET (image);
+}
+
 /**
  * gtk_image_set_from_pixmap:
  * @image: a #GtkImage
@@ -376,7 +415,7 @@ void
 gtk_image_set_from_file   (GtkImage    *image,
                            const gchar *filename)
 {
-  GdkPixbuf *pixbuf;
+  GdkPixbufAnimation *anim;
   
   g_return_if_fail (GTK_IS_IMAGE (image));
   g_return_if_fail (filename != NULL);
@@ -386,9 +425,9 @@ gtk_image_set_from_file   (GtkImage    *image,
   if (filename == NULL)
     return;
   
-  pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
+  anim = gdk_pixbuf_animation_new_from_file (filename, NULL);
 
-  if (pixbuf == NULL)
+  if (anim == NULL)
     {
       gtk_image_set_from_stock (image,
                                 GTK_STOCK_MISSING_IMAGE,
@@ -396,9 +435,22 @@ gtk_image_set_from_file   (GtkImage    *image,
       return;
     }
 
-  gtk_image_set_from_pixbuf (image, pixbuf);
+  /* We could just unconditionally set_from_animation,
+   * but it's nicer for memory if we toss the animation
+   * if it's just a single pixbuf
+   */
 
-  g_object_unref (G_OBJECT (pixbuf));
+  if (gdk_pixbuf_animation_is_static_image (anim))
+    {
+      gtk_image_set_from_pixbuf (image,
+                                 gdk_pixbuf_animation_get_static_image (anim));
+    }
+  else
+    {
+      gtk_image_set_from_animation (image, anim);
+    }
+
+  g_object_unref (G_OBJECT (anim));
 }
 
 /**
@@ -500,6 +552,41 @@ gtk_image_set_from_icon_set  (GtkImage       *image,
     }
 }
 
+/**
+ * gtk_image_set_from_animation:
+ * @image: a #GtkImage
+ * @animation: the #GdkPixbufAnimation
+ * 
+ * Causes the #GtkImage to display the given animation (or display
+ * nothing, if you set the animation to %NULL).
+ **/
+void
+gtk_image_set_from_animation (GtkImage           *image,
+                              GdkPixbufAnimation *animation)
+{
+  g_return_if_fail (GTK_IS_IMAGE (image));
+  g_return_if_fail (animation == NULL ||
+                    GDK_IS_PIXBUF_ANIMATION (animation));
+  
+  if (animation)
+    g_object_ref (G_OBJECT (animation));
+
+  gtk_image_reset (image);
+
+  if (animation != NULL)
+    {
+      image->storage_type = GTK_IMAGE_ANIMATION;
+
+      image->data.anim.anim = animation;
+      image->data.anim.frame_timeout = 0;
+      image->data.anim.iter = NULL;
+      
+      gtk_image_update_size (image,
+                             gdk_pixbuf_animation_get_width (animation),
+                             gdk_pixbuf_animation_get_height (animation));
+    }
+}
+
 /**
  * gtk_image_get_storage_type:
  * @image: a #GtkImage
@@ -660,6 +747,33 @@ gtk_image_get_icon_set  (GtkImage        *image,
     *size = image->data.icon_set.size;
 }
 
+/**
+ * gtk_image_get_animation:
+ * @image: a #GtkImage
+ *
+ *
+ * Gets the #GdkPixbufAnimation being displayed by the #GtkImage.
+ * The storage type of the image must be %GTK_IMAGE_EMPTY or
+ * %GTK_IMAGE_ANIMATION (see gtk_image_get_storage_type()).
+ * The caller of this function does not own a reference to the
+ * returned animation.
+ * 
+ * Return value: the displayed animation, or %NULL if the image is empty
+ **/
+GdkPixbufAnimation*
+gtk_image_get_animation (GtkImage *image)
+{
+  g_return_val_if_fail (GTK_IS_IMAGE (image), NULL);
+  g_return_val_if_fail (image->storage_type == GTK_IMAGE_ANIMATION ||
+                        image->storage_type == GTK_IMAGE_EMPTY,
+                        NULL);
+
+  if (image->storage_type == GTK_IMAGE_EMPTY)
+    image->data.anim.anim = NULL;
+  
+  return image->data.anim.anim;
+}
+
 GtkWidget*
 gtk_image_new (GdkImage  *val,
               GdkBitmap *mask)
@@ -695,6 +809,55 @@ gtk_image_get (GtkImage   *image,
   gtk_image_get_image (image, val, mask);
 }
 
+static void
+gtk_image_unmap (GtkWidget *widget)
+{
+  GtkImage *image;
+
+  image = GTK_IMAGE (widget);
+
+  if (image->storage_type == GTK_IMAGE_ANIMATION)
+    {
+      /* Reset the animation */
+      
+      if (image->data.anim.frame_timeout)
+        {
+          g_source_remove (image->data.anim.frame_timeout);
+          image->data.anim.frame_timeout = 0;
+        }
+
+      if (image->data.anim.iter)
+        {
+          g_object_unref (G_OBJECT (image->data.anim.iter));
+          image->data.anim.iter = NULL;
+        }
+    }
+
+  if (GTK_WIDGET_CLASS (parent_class)->unmap)
+    GTK_WIDGET_CLASS (parent_class)->unmap (widget);
+}
+
+gint
+animation_timeout (gpointer data)
+{
+  GtkImage *image;
+
+  image = GTK_IMAGE (data);
+  
+  image->data.anim.frame_timeout = 0;
+
+  gdk_pixbuf_animation_iter_advance (image->data.anim.iter, NULL);
+
+  if (gdk_pixbuf_animation_iter_get_delay_time (image->data.anim.iter) >= 0)
+    image->data.anim.frame_timeout =
+      g_timeout_add (gdk_pixbuf_animation_iter_get_delay_time (image->data.anim.iter),
+                     animation_timeout,
+                     image);
+  
+  gtk_widget_queue_draw (GTK_WIDGET (image));
+
+  return FALSE;
+}
 
 static gint
 gtk_image_expose (GtkWidget      *widget,
@@ -777,6 +940,24 @@ gtk_image_expose (GtkWidget      *widget,
               image_bound.height = gdk_pixbuf_get_height (stock_pixbuf);
             }
           break;
+
+        case GTK_IMAGE_ANIMATION:
+          {
+            if (image->data.anim.iter == NULL)
+              {
+                image->data.anim.iter = gdk_pixbuf_animation_get_iter (image->data.anim.anim, NULL);
+                
+                if (gdk_pixbuf_animation_iter_get_delay_time (image->data.anim.iter) >= 0)
+                  image->data.anim.frame_timeout =
+                    g_timeout_add (gdk_pixbuf_animation_iter_get_delay_time (image->data.anim.iter),
+                                   animation_timeout,
+                                   image);
+              }
+
+            image_bound.width = gdk_pixbuf_animation_get_width (image->data.anim.anim);
+            image_bound.height = gdk_pixbuf_animation_get_height (image->data.anim.anim);
+          }
+          break;
           
         default:
           break;
@@ -849,6 +1030,25 @@ gtk_image_expose (GtkWidget      *widget,
                 }
               break;
 
+            case GTK_IMAGE_ANIMATION:
+              /* don't advance the anim iter here, or we could get frame changes between two
+               * exposes of different areas.
+               */
+              
+              gdk_pixbuf_render_to_drawable_alpha (gdk_pixbuf_animation_iter_get_pixbuf (image->data.anim.iter),
+                                                   widget->window,
+                                                   image_bound.x - x,
+                                                   image_bound.y - y,
+                                                   image_bound.x,
+                                                   image_bound.y,
+                                                   image_bound.width,
+                                                   image_bound.height,
+                                                   GDK_PIXBUF_ALPHA_FULL,
+                                                   128,
+                                                   GDK_RGB_DITHER_NORMAL,
+                                                   0, 0);
+              break;
+              
             default:
               break;
             }
@@ -876,9 +1076,6 @@ gtk_image_clear (GtkImage *image)
       if (image->data.pixmap.mask)
         g_object_unref (G_OBJECT (image->data.pixmap.mask));
 
-      image->data.pixmap.pixmap = NULL;
-      image->data.pixmap.mask = NULL;
-
       break;
 
     case GTK_IMAGE_IMAGE:
@@ -889,9 +1086,6 @@ gtk_image_clear (GtkImage *image)
       if (image->data.image.mask)
         g_object_unref (G_OBJECT (image->data.image.mask));
 
-      image->data.image.image = NULL;
-      image->data.image.mask = NULL;
-
       break;
 
     case GTK_IMAGE_PIXBUF:
@@ -899,27 +1093,27 @@ gtk_image_clear (GtkImage *image)
       if (image->data.pixbuf.pixbuf)
         g_object_unref (G_OBJECT (image->data.pixbuf.pixbuf));
 
-      image->data.pixbuf.pixbuf = NULL;
-
       break;
 
     case GTK_IMAGE_STOCK:
 
       g_free (image->data.stock.stock_id);
-
-      image->data.stock.stock_id = NULL;
-      image->data.stock.size = 0;
       
       break;
 
     case GTK_IMAGE_ICON_SET:
       if (image->data.icon_set.icon_set)
         gtk_icon_set_unref (image->data.icon_set.icon_set);
-
-      image->data.icon_set.size = 0;
-      image->data.icon_set.icon_set = NULL;
       
       break;
+
+    case GTK_IMAGE_ANIMATION:
+      if (image->data.anim.frame_timeout)
+        g_source_remove (image->data.anim.frame_timeout);
+
+      if (image->data.anim.anim)
+        g_object_unref (G_OBJECT (image->data.anim.anim));      
+      break;
       
     case GTK_IMAGE_EMPTY:
     default:
@@ -928,6 +1122,8 @@ gtk_image_clear (GtkImage *image)
     }
 
   image->storage_type = GTK_IMAGE_EMPTY;
+
+  memset (&image->data, '\0', sizeof (image->data));
 }
 
 static void
index bc1a0c0a6075289e1aa7c430340de70b281d8904..71c80dfd0a1389b7743e0e7f46aebb9e0f793ec3 100644 (file)
@@ -52,6 +52,7 @@ typedef struct _GtkImageImageData   GtkImageImageData;
 typedef struct _GtkImagePixbufData  GtkImagePixbufData;
 typedef struct _GtkImageStockData   GtkImageStockData;
 typedef struct _GtkImageIconSetData GtkImageIconSetData;
+typedef struct _GtkImageAnimationData GtkImageAnimationData;
 
 struct _GtkImagePixmapData
 {
@@ -82,6 +83,13 @@ struct _GtkImageIconSetData
   GtkIconSize size;
 };
 
+struct _GtkImageAnimationData
+{
+  GdkPixbufAnimation *anim;
+  GdkPixbufAnimationIter *iter;
+  guint frame_timeout;
+};
+
 typedef enum
 {
   GTK_IMAGE_EMPTY,
@@ -89,7 +97,8 @@ typedef enum
   GTK_IMAGE_IMAGE,
   GTK_IMAGE_PIXBUF,
   GTK_IMAGE_STOCK,
-  GTK_IMAGE_ICON_SET
+  GTK_IMAGE_ICON_SET,
+  GTK_IMAGE_ANIMATION
 } GtkImageType;
 
 struct _GtkImage
@@ -105,6 +114,7 @@ struct _GtkImage
     GtkImagePixbufData pixbuf;
     GtkImageStockData stock;
     GtkImageIconSetData icon_set;
+    GtkImageAnimationData anim;
   } data;
 };
 
@@ -115,33 +125,36 @@ struct _GtkImageClass
 
 GtkType    gtk_image_get_type (void) G_GNUC_CONST;
 
-GtkWidget* gtk_image_new_from_pixmap   (GdkPixmap       *pixmap,
-                                        GdkBitmap       *mask);
-GtkWidget* gtk_image_new_from_image    (GdkImage        *image,
-                                        GdkBitmap       *mask);
-GtkWidget* gtk_image_new_from_file     (const gchar     *filename);
-GtkWidget* gtk_image_new_from_pixbuf   (GdkPixbuf       *pixbuf);
-GtkWidget* gtk_image_new_from_stock    (const gchar     *stock_id,
-                                        GtkIconSize      size);
-GtkWidget* gtk_image_new_from_icon_set (GtkIconSet      *icon_set,
-                                        GtkIconSize      size);
-
-void gtk_image_set_from_pixmap   (GtkImage        *image,
-                                  GdkPixmap       *pixmap,
-                                  GdkBitmap       *mask);
-void gtk_image_set_from_image    (GtkImage        *image,
-                                  GdkImage        *gdk_image,
-                                  GdkBitmap       *mask);
-void gtk_image_set_from_file     (GtkImage        *image,
-                                  const gchar     *filename);
-void gtk_image_set_from_pixbuf   (GtkImage        *image,
-                                  GdkPixbuf       *pixbuf);
-void gtk_image_set_from_stock    (GtkImage        *image,
-                                  const gchar     *stock_id,
-                                  GtkIconSize      size);
-void gtk_image_set_from_icon_set (GtkImage        *image,
-                                  GtkIconSet      *icon_set,
-                                  GtkIconSize      size);
+GtkWidget* gtk_image_new_from_pixmap    (GdkPixmap       *pixmap,
+                                         GdkBitmap       *mask);
+GtkWidget* gtk_image_new_from_image     (GdkImage        *image,
+                                         GdkBitmap       *mask);
+GtkWidget* gtk_image_new_from_file      (const gchar     *filename);
+GtkWidget* gtk_image_new_from_pixbuf    (GdkPixbuf       *pixbuf);
+GtkWidget* gtk_image_new_from_stock     (const gchar     *stock_id,
+                                         GtkIconSize      size);
+GtkWidget* gtk_image_new_from_icon_set  (GtkIconSet      *icon_set,
+                                         GtkIconSize      size);
+GtkWidget* gtk_image_new_from_animation (GdkPixbufAnimation *animation);
+
+void gtk_image_set_from_pixmap    (GtkImage        *image,
+                                   GdkPixmap       *pixmap,
+                                   GdkBitmap       *mask);
+void gtk_image_set_from_image     (GtkImage        *image,
+                                   GdkImage        *gdk_image,
+                                   GdkBitmap       *mask);
+void gtk_image_set_from_file      (GtkImage        *image,
+                                   const gchar     *filename);
+void gtk_image_set_from_pixbuf    (GtkImage        *image,
+                                   GdkPixbuf       *pixbuf);
+void gtk_image_set_from_stock     (GtkImage        *image,
+                                   const gchar     *stock_id,
+                                   GtkIconSize      size);
+void gtk_image_set_from_icon_set  (GtkImage        *image,
+                                   GtkIconSet      *icon_set,
+                                   GtkIconSize      size);
+void gtk_image_set_from_animation (GtkImage           *image,
+                                   GdkPixbufAnimation *animation);
 
 GtkImageType gtk_image_get_storage_type (GtkImage   *image);
 
@@ -158,6 +171,7 @@ void       gtk_image_get_stock    (GtkImage         *image,
 void       gtk_image_get_icon_set (GtkImage         *image,
                                    GtkIconSet      **icon_set,
                                    GtkIconSize      *size);
+GdkPixbufAnimation* gtk_image_get_animation (GtkImage *image);
 
 
 #ifndef GTK_DISABLE_DEPRECATED
index 12ec4108db46c97b6fd85e699eaddf5d70ce8d57..cb656a25cda75c5252485f61d13ab187a9b4b252 100644 (file)
@@ -36,6 +36,7 @@ NONE:INT,INT
 NONE:NONE
 NONE:POINTER
 NONE:STRING,INT,POINTER
+STRING:DOUBLE
 VOID:BOOLEAN
 VOID:BOXED
 VOID:BOXED,BOXED
index 12ec4108db46c97b6fd85e699eaddf5d70ce8d57..cb656a25cda75c5252485f61d13ab187a9b4b252 100644 (file)
@@ -36,6 +36,7 @@ NONE:INT,INT
 NONE:NONE
 NONE:POINTER
 NONE:STRING,INT,POINTER
+STRING:DOUBLE
 VOID:BOOLEAN
 VOID:BOXED
 VOID:BOXED,BOXED
index b9c27307b94d406dd64573be7cd410f9258c3758..58fb89a38663282f0f97b678ae70255f6ff0467f 100644 (file)
@@ -91,13 +91,14 @@ struct _GtkRangeClass
   guint8 slider;
   guint8 step_forw;
   guint8 step_back;
-
+  
   /* action signals for keybindings */
   void (* move_slider)      (GtkRange     *range,
                              GtkScrollType scroll,
                              GtkTroughType trough);
 
   /* Completely broken virtual functions, please ignore */
+
   void (* draw_background)  (GtkRange *range);
   void (* clear_background) (GtkRange *range);
   void (* draw_trough)      (GtkRange *range);
index a2769b285132bc043a72aa5d14ab3cc508734d93..992cdfe41d5b53eec26e24b2bba825fdf235fd99 100644 (file)
@@ -27,6 +27,7 @@
 #include <math.h>
 #include "gtkintl.h"
 #include "gtkscale.h"
+#include "gtkmarshal.h"
 
 enum {
   ARG_0,
@@ -35,6 +36,12 @@ enum {
   ARG_VALUE_POS
 };
 
+enum {
+  FORMAT_VALUE,
+  LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
 
 static void gtk_scale_class_init      (GtkScaleClass *klass);
 static void gtk_scale_init            (GtkScale      *scale);
@@ -78,6 +85,22 @@ gtk_scale_get_type (void)
   return scale_type;
 }
 
+gboolean
+single_string_accumulator (GSignalInvocationHint *ihint,
+                           GValue                *return_accu,
+                           const GValue          *handler_return,
+                           gpointer               dummy)
+{
+  gboolean continue_emission;
+  gchar *str;
+  
+  str = g_value_get_string (handler_return);
+  g_value_set_string (return_accu, str);
+  continue_emission = str == NULL;
+  
+  return continue_emission;
+}
+
 static void
 gtk_scale_class_init (GtkScaleClass *class)
 {
@@ -104,6 +127,16 @@ gtk_scale_class_init (GtkScaleClass *class)
                           GTK_ARG_READWRITE,
                           ARG_VALUE_POS);
 
+  signals[FORMAT_VALUE] =
+    g_signal_newc ("format_value",
+                  G_TYPE_FROM_CLASS (object_class),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (GtkScaleClass, format_value),
+                  single_string_accumulator, NULL,
+                  gtk_marshal_STRING__DOUBLE,
+                  G_TYPE_STRING, 1,
+                  G_TYPE_DOUBLE);
+  
   object_class->set_arg = gtk_scale_set_arg;
   object_class->get_arg = gtk_scale_get_arg;
 
@@ -280,58 +313,27 @@ gtk_scale_get_value_size (GtkScale *scale,
     {
       PangoLayout *layout;
       PangoRectangle logical_rect;
-      gchar buffer[128];
-      gdouble value;
-      gint digits;
-      gint i, j;
+      gchar *txt;
       
       range = GTK_RANGE (scale);
 
       layout = gtk_widget_create_pango_layout (GTK_WIDGET (scale), NULL);
 
-      value = ABS (range->adjustment->lower);
-      if (value == 0) value = 1;
-      digits = log10 (value) + 1;
-      if (digits > 13)
-       digits = 13;
-
-      i = 0;
-      if (range->adjustment->lower < 0)
-        buffer[i++] = '-';
-      for (j = 0; j < digits; j++)
-        buffer[i++] = '0';
-      if (GTK_RANGE (scale)->digits)
-        buffer[i++] = '.';
-      for (j = 0; j < GTK_RANGE (scale)->digits; j++)
-        buffer[i++] = '0';
-      buffer[i] = '\0';
-
-      pango_layout_set_text (layout, buffer, i);
+      txt = _gtk_scale_format_value (scale, range->adjustment->lower);
+      pango_layout_set_text (layout, txt, -1);
+      g_free (txt);
+      
       pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
 
       if (width)
        *width = logical_rect.width;
       if (height)
-       *height = logical_rect.width;
+       *height = logical_rect.height;
+
+      txt = _gtk_scale_format_value (scale, range->adjustment->upper);
+      pango_layout_set_text (layout, txt, -1);
+      g_free (txt);
       
-      value = ABS (range->adjustment->upper);
-      if (value == 0) value = 1;
-      digits = log10 (value) + 1;
-      if (digits > 13)
-        digits = 13;
-
-      i = 0;
-      if (range->adjustment->upper < 0)
-        buffer[i++] = '-';
-      for (j = 0; j < digits; j++)
-        buffer[i++] = '0';
-      if (GTK_RANGE (scale)->digits)
-        buffer[i++] = '.';
-      for (j = 0; j < GTK_RANGE (scale)->digits; j++)
-        buffer[i++] = '0';
-      buffer[i] = '\0';
-
-      pango_layout_set_text (layout, buffer, i);
       pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
 
       if (width)
@@ -383,3 +385,32 @@ gtk_scale_draw_background (GtkRange *range)
 
   gtk_scale_draw_value (GTK_SCALE (range));
 }
+
+/**
+ * _gtk_scale_format_value:
+ * @scale: a #GtkScale
+ * @value: adjustment value
+ * 
+ * Emits "format_value" signal to format the value, if no user
+ * signal handlers, falls back to a default format.
+ * 
+ * Return value: formatted value
+ **/
+gchar*
+_gtk_scale_format_value (GtkScale *scale,
+                         gdouble   value)
+{
+  gchar *fmt = NULL;
+
+  g_signal_emit (G_OBJECT (scale),
+                 signals[FORMAT_VALUE],
+                 0,
+                 value,
+                 &fmt);
+
+  if (fmt)
+    return fmt;
+  else
+    return g_strdup_printf ("%0.*f", GTK_RANGE (scale)->digits,
+                            value);
+}
index fd9e97446d647525b8367c12325dfbe408ef9d2c..b6cd71954701823b6badcf57cc2c474a9ce62f30 100644 (file)
@@ -61,6 +61,9 @@ struct _GtkScaleClass
   GtkRangeClass parent_class;
 
   gint value_spacing;
+
+  gchar* (* format_value) (GtkRange *range,
+                           gdouble   value);  
   
   void (* draw_value) (GtkScale *scale);
 };
@@ -79,6 +82,9 @@ void    gtk_scale_get_value_size  (GtkScale        *scale,
 
 void    gtk_scale_draw_value      (GtkScale        *scale);
 
+gchar  *_gtk_scale_format_value   (GtkScale        *scale,
+                                   gdouble          value);
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
index 1074ca0f9a0cf7db8e97dcd1adb33ee8d5c82569..2e30d026ac4cdf0bd8dfe2f6274bc6b4513e7184 100644 (file)
@@ -2106,6 +2106,127 @@ gtk_text_buffer_remove_tag_by_name (GtkTextBuffer *buffer,
   gtk_text_buffer_emit_tag (buffer, tag, FALSE, start, end);
 }
 
+static gint
+pointer_cmp (gconstpointer a,
+             gconstpointer b)
+{
+  if (a < b)
+    return -1;
+  else if (a > b)
+    return 1;
+  else
+    return 0;
+}
+
+/**
+ * gtk_text_buffer_remove_all_tags:
+ * @buffer: a #GtkTextBuffer
+ * @start: one bound of range to be untagged
+ * @end: other bound of range to be untagged
+ * 
+ * Removes all tags in the range between @start and @end.  Be careful
+ * with this function; it could remove tags added in code unrelated to
+ * the code you're currently writing. That is, using this function is
+ * probably a bad idea if you have two or more unrelated code sections
+ * that add tags.
+ **/
+void
+gtk_text_buffer_remove_all_tags (GtkTextBuffer     *buffer,
+                                 const GtkTextIter *start,
+                                 const GtkTextIter *end)
+{
+  GtkTextIter first, second, tmp;
+  GSList *tags;
+  GSList *tmp_list;
+  GSList *prev;
+  GtkTextTag *tag;
+  
+  g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
+  g_return_if_fail (start != NULL);
+  g_return_if_fail (end != NULL);
+  
+  first = *start;
+  second = *end;
+
+  gtk_text_iter_reorder (&first, &second);
+
+  /* Get all tags turned on at the start */
+  tags = gtk_text_iter_get_tags (&first);
+  
+  /* Find any that are toggled on within the range */
+  tmp = first;
+  while (gtk_text_iter_forward_to_tag_toggle (&tmp, NULL))
+    {
+      GSList *toggled;
+      GSList *tmp_list2;
+
+      if (gtk_text_iter_compare (&tmp, &second) >= 0)
+        break; /* past the end of the range */
+      
+      toggled = gtk_text_iter_get_toggled_tags (&tmp, TRUE);
+
+      /* We could end up with a really big-ass list here.
+       * Fix it someday.
+       */
+      tmp_list2 = toggled;
+      while (tmp_list2 != NULL)
+        {
+          tags = g_slist_prepend (tags, tmp_list2->data);
+
+          tmp_list2 = g_slist_next (tmp_list2);
+        }
+
+      g_slist_free (toggled);
+    }
+  
+  /* Sort the list */
+  tags = g_slist_sort (tags, pointer_cmp);
+
+  /* Strip duplicates */
+  tag = NULL;
+  prev = NULL;
+  tmp_list = tags;
+  while (tmp_list != NULL)
+    {
+      if (tag == tmp_list->data)
+        {
+          /* duplicate */
+          if (prev)
+            prev->next = tmp_list->next;
+
+          tmp_list->next = NULL;
+
+          g_slist_free (tmp_list);
+
+          tmp_list = prev->next;
+          /* prev is unchanged */
+        }
+      else
+        {
+          /* not a duplicate */
+          tag = GTK_TEXT_TAG (tmp_list->data);
+          prev = tmp_list;
+          tmp_list = tmp_list->next;
+        }
+    }
+
+  g_list_foreach (tags, (GFunc) g_object_ref, NULL);
+  
+  tmp_list = tags;
+  while (tmp_list != NULL)
+    {
+      tag = GTK_TEXT_TAG (tmp_list->data);
+
+      gtk_text_buffer_remove_tag (buffer, tag, &first, &second);
+      
+      tmp_list = tmp_list->next;
+    }
+
+  g_list_foreach (tags, (GFunc) g_object_unref, NULL);
+  
+  g_slist_free (tags);
+}
+
 
 /*
  * Obtain various iterators
index b6f801f11994e2e7808675e7dad170df07cb1d96..4368d242aa174a37c1c994f5766e4c6e831cf29b 100644 (file)
@@ -266,6 +266,9 @@ void gtk_text_buffer_remove_tag_by_name    (GtkTextBuffer     *buffer,
                                             const gchar       *name,
                                             const GtkTextIter *start,
                                             const GtkTextIter *end);
+void gtk_text_buffer_remove_all_tags       (GtkTextBuffer     *buffer,
+                                            const GtkTextIter *start,
+                                            const GtkTextIter *end);
 
 
 /* You can either ignore the return value, or use it to
index 241529d389564dc10d6b74250ad82fee9cfc98ae..1d530321461038c1e30b630582b112808d542950 100644 (file)
@@ -1511,7 +1511,7 @@ gtk_text_iter_is_end (const GtkTextIter *iter)
 }
 
 /**
- * gtk_text_iter_is_first:
+ * gtk_text_iter_is_start:
  * @iter: an iterator
  *
  * Returns TRUE if @iter is the first iterator in the buffer, that is
@@ -1520,7 +1520,7 @@ gtk_text_iter_is_end (const GtkTextIter *iter)
  * Return value: whether @iter is the first in the buffer
  **/
 gboolean
-gtk_text_iter_is_first (const GtkTextIter *iter)
+gtk_text_iter_is_start (const GtkTextIter *iter)
 {
   return gtk_text_iter_get_offset (iter) == 0;
 }
@@ -4253,7 +4253,7 @@ lines_window_init (LinesWindow       *win,
   /* If we start on line 1, there are 2 lines to search (0 and 1), so
    * n_lines can be 2.
    */
-  if (gtk_text_iter_is_first (start) ||
+  if (gtk_text_iter_is_start (start) ||
       gtk_text_iter_get_line (start) + 1 < win->n_lines)
     {
       /* Already at the end, or not enough lines to match */
index 00285e287b9ba09bef5b8b9b4392402520f50100..8a883f9b23acbb6c6d8ef51d7222f83796c01567 100644 (file)
@@ -108,9 +108,10 @@ GSList  *  gtk_text_iter_get_marks  (const GtkTextIter *iter);
 GtkTextChildAnchor* gtk_text_iter_get_child_anchor (const GtkTextIter *iter);
 
 /* Return list of tags toggled at this point (toggled_on determines
-   whether the list is of on-toggles or off-toggles) */
+ * whether the list is of on-toggles or off-toggles)
+ */
 GSList  *gtk_text_iter_get_toggled_tags  (const GtkTextIter  *iter,
-                                          gboolean             toggled_on);
+                                          gboolean            toggled_on);
 
 gboolean gtk_text_iter_begins_tag        (const GtkTextIter  *iter,
                                           GtkTextTag         *tag);
@@ -145,7 +146,7 @@ gboolean gtk_text_iter_get_attributes    (const GtkTextIter    *iter,
                                           GtkTextAttributes    *values);
 gchar*   gtk_text_iter_get_language      (const GtkTextIter    *iter);
 gboolean gtk_text_iter_is_end            (const GtkTextIter    *iter);
-gboolean gtk_text_iter_is_first          (const GtkTextIter    *iter);
+gboolean gtk_text_iter_is_start          (const GtkTextIter    *iter);
 
 /*
  * Moving around the buffer
index 1355ef8fffe072846411b2dd49e5d2babb98f73e..208fa8c0ea805b071393a8add6094ba9386bb462 100644 (file)
@@ -1280,6 +1280,16 @@ add_text_attrs (GtkTextLayout      *layout,
   attr->end_index = start + byte_count;
 
   pango_attr_list_insert (attrs, attr);
+
+  if (style->font_scale != 1.0)
+    {
+      attr = pango_attr_scale_new (style->font_scale);
+
+      attr->start_index = start;
+      attr->end_index = start + byte_count;
+      
+      pango_attr_list_insert (attrs, attr);
+    }
 }
 
 static void
index a652432301dcc5efdd7714f9256941dcaf6f81e3..c149c4edadf3ea3dbf7a770e911f998894836ca3 100644 (file)
@@ -85,6 +85,7 @@ enum {
   PROP_STRETCH,
   PROP_SIZE,
   PROP_SIZE_POINTS,
+  PROP_SCALE,
   PROP_PIXELS_ABOVE_LINES,
   PROP_PIXELS_BELOW_LINES,
   PROP_PIXELS_INSIDE_WRAP,
@@ -114,6 +115,7 @@ enum {
   PROP_WEIGHT_SET,
   PROP_STRETCH_SET,
   PROP_SIZE_SET,
+  PROP_SCALE_SET,
   PROP_PIXELS_ABOVE_LINES_SET,
   PROP_PIXELS_BELOW_LINES_SET,
   PROP_PIXELS_INSIDE_WRAP_SET,
@@ -349,6 +351,16 @@ gtk_text_tag_class_init (GtkTextTagClass *klass)
                                                      0,
                                                      G_PARAM_READABLE | G_PARAM_WRITABLE));
 
+  g_object_class_install_property (object_class,
+                                   PROP_SCALE,
+                                   g_param_spec_double ("scale",
+                                                        _("Font scale"),
+                                                        _("Font scale"),
+                                                        0.0,
+                                                        G_MAXDOUBLE,
+                                                        1.0,
+                                                        G_PARAM_READABLE | G_PARAM_WRITABLE));
+  
   g_object_class_install_property (object_class,
                                    PROP_SIZE_POINTS,
                                    g_param_spec_double ("size_points",
@@ -543,6 +555,10 @@ gtk_text_tag_class_init (GtkTextTagClass *klass)
                 _("Font size set"),
                 _("Whether this tag affects the font size"));
 
+  ADD_SET_PROP ("scale_set", PROP_SCALE_SET,
+                _("Font scale set"),
+                _("Whether this tag scales the font size by a factor"));
+  
   ADD_SET_PROP ("justification_set", PROP_JUSTIFICATION_SET,
                 _("Justification set"),
                 _("Whether this tag affects paragraph justification"));
@@ -963,6 +979,12 @@ gtk_text_tag_set_property (GObject      *object,
       size_changed = TRUE;
       break;
 
+    case PROP_SCALE:
+      text_tag->values->font_scale = g_value_get_double (value);
+      text_tag->scale_set = TRUE;
+      size_changed = TRUE;
+      break;
+      
     case PROP_SIZE_POINTS:
       text_tag->values->font.size = g_value_get_double (value) * PANGO_SCALE;
       text_tag->size_set = TRUE;
@@ -1151,6 +1173,11 @@ gtk_text_tag_set_property (GObject      *object,
       text_tag->size_set = g_value_get_boolean (value);
       size_changed = TRUE;
       break;
+
+    case PROP_SCALE_SET:
+      text_tag->scale_set = g_value_get_boolean (value);
+      size_changed = TRUE;
+      break;
       
     case PROP_PIXELS_ABOVE_LINES_SET:
       text_tag->pixels_above_lines_set = g_value_get_boolean (value);
@@ -1332,10 +1359,14 @@ gtk_text_tag_get_property (GObject      *object,
     case PROP_SIZE:
       g_value_set_int (value,  tag->values->font.size);
       break;
-
+      
     case PROP_SIZE_POINTS:
       g_value_set_double (value, ((double)tag->values->font.size) / (double)PANGO_SCALE);
       break;
+
+    case PROP_SCALE:
+      g_value_set_double (value, tag->values->font_scale);
+      break;
       
     case PROP_PIXELS_ABOVE_LINES:
       g_value_set_int (value,  tag->values->pixels_above_lines);
@@ -1445,6 +1476,10 @@ gtk_text_tag_get_property (GObject      *object,
     case PROP_SIZE_SET:
       g_value_set_boolean (value, tag->size_set);
       break;
+
+    case PROP_SCALE_SET:
+      g_value_set_boolean (value, tag->scale_set);
+      break;
       
     case PROP_PIXELS_ABOVE_LINES_SET:
       g_value_set_boolean (value, tag->pixels_above_lines_set);
@@ -1724,6 +1759,8 @@ gtk_text_attributes_new (void)
 
   values->language = gtk_get_default_language ();
 
+  values->font_scale = 1.0;
+  
   return values;
 }
 
@@ -1965,6 +2002,10 @@ _gtk_text_attributes_fill_from_tags (GtkTextAttributes *dest,
       if (tag->size_set)
         dest->font.size = vals->font.size;
 
+      /* multiply all the scales together to get a composite */
+      if (tag->scale_set)
+        dest->font_scale *= vals->font_scale;
+      
       if (tag->justification_set)
         dest->justification = vals->justification;
 
@@ -2038,6 +2079,7 @@ _gtk_text_tag_affects_size (GtkTextTag *tag)
     tag->variant_set ||
     tag->weight_set ||
     tag->size_set ||
+    tag->scale_set ||
     tag->stretch_set ||
     tag->justification_set ||
     tag->left_margin_set ||
index ea30059b75cccb862ab024f49c4206f82321adeb..f75a1760b0635991ef4381bca7eaebf7ee6e268e 100644 (file)
@@ -60,6 +60,7 @@ struct _GtkTextTag
   guint weight_set : 1;
   guint stretch_set : 1;
   guint size_set : 1;
+  guint scale_set : 1;
   guint fg_stipple_set : 1;
   guint justification_set : 1;
   guint left_margin_set : 1;
@@ -148,6 +149,8 @@ struct _GtkTextAttributes
   /* Individual chunks of this can be set/unset as a group */
   PangoFontDescription font;
 
+  gdouble font_scale;
+  
   gint left_margin;
 
   gint indent;  
index 26aa7c698002bec2dc7be9a699230ec326fd106b..8bb7314b47c823bcde7ce3e9c32065f5f01ba137 100644 (file)
@@ -506,6 +506,7 @@ gtk_text_view_class_init (GtkTextViewClass *klass)
                            GTK_ARG_READWRITE, ARG_PIXELS_INSIDE_WRAP);
   gtk_object_add_arg_type ("GtkTextView::editable", GTK_TYPE_BOOL,
                            GTK_ARG_READWRITE, ARG_EDITABLE);
+
   gtk_object_add_arg_type ("GtkTextView::wrap_mode", GTK_TYPE_WRAP_MODE,
                            GTK_ARG_READWRITE, ARG_WRAP_MODE);
   gtk_object_add_arg_type ("GtkTextView::justify", GTK_TYPE_JUSTIFICATION,
index 72b8b209aa9b0961ea1f44d26579e724cc7716ca..be31ec33788a74ab812e6457ab28eb7ca36ff9d2 100644 (file)
@@ -532,7 +532,6 @@ gtk_vscale_draw_value (GtkScale *scale)
 {
   GtkStateType state_type;
   GtkWidget *widget;
-  gchar buffer[32];
   gint width, height;
   gint x, y;
   
@@ -545,10 +544,14 @@ gtk_vscale_draw_value (GtkScale *scale)
     {
       PangoLayout *layout;
       PangoRectangle logical_rect;
+      gchar *txt;
+      
+      txt = _gtk_scale_format_value (scale,
+                                     GTK_RANGE (scale)->adjustment->value);
+      
+      layout = gtk_widget_create_pango_layout (widget, txt);
+      g_free (txt);
       
-      sprintf (buffer, "%0.*f", GTK_RANGE (scale)->digits, GTK_RANGE (scale)->adjustment->value);
-
-      layout = gtk_widget_create_pango_layout (widget, buffer);
       pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
 
       switch (scale->value_pos)
index 5cd9117aa6c50629d15b1018e33a89484dc5b790..084ad2ae5ca85fe48d35fd678f6ccebda9f92a88 100644 (file)
@@ -6511,6 +6511,13 @@ create_event_watcher (void)
  * GtkRange
  */
 
+static gchar*
+reformat_value (GtkScale *scale,
+                gdouble   value)
+{
+  return g_strdup_printf ("-->%g<--", value);
+}
+
 static void
 create_range_controls (void)
 {
@@ -6563,6 +6570,15 @@ create_range_controls (void)
       gtk_box_pack_start (GTK_BOX (box2), scrollbar, TRUE, TRUE, 0);
       gtk_widget_show (scrollbar);
 
+      scale = gtk_hscale_new (GTK_ADJUSTMENT (adjustment));
+      gtk_scale_set_draw_value (GTK_SCALE (scale), TRUE);
+      gtk_signal_connect (GTK_OBJECT (scale),
+                          "format_value",
+                          GTK_SIGNAL_FUNC (reformat_value),
+                          NULL);
+      gtk_box_pack_start (GTK_BOX (box2), scale, TRUE, TRUE, 0);
+      gtk_widget_show (scale);
+      
       hbox = gtk_hbox_new (FALSE, 0);
 
       scale = gtk_vscale_new (GTK_ADJUSTMENT (adjustment));
@@ -6579,10 +6595,20 @@ create_range_controls (void)
       gtk_range_set_inverted (GTK_RANGE (scale), TRUE);
       gtk_box_pack_start (GTK_BOX (hbox), scale, TRUE, TRUE, 0);
       gtk_widget_show (scale);
+
+      scale = gtk_vscale_new (GTK_ADJUSTMENT (adjustment));
+      gtk_scale_set_draw_value (GTK_SCALE (scale), TRUE);
+      gtk_signal_connect (GTK_OBJECT (scale),
+                          "format_value",
+                          GTK_SIGNAL_FUNC (reformat_value),
+                          NULL);
+      gtk_box_pack_start (GTK_BOX (hbox), scale, TRUE, TRUE, 0);
+      gtk_widget_show (scale);
+
       
       gtk_box_pack_start (GTK_BOX (box2), hbox, TRUE, TRUE, 0);
       gtk_widget_show (hbox);
-
+      
       separator = gtk_hseparator_new ();
       gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0);
       gtk_widget_show (separator);
@@ -8158,9 +8184,14 @@ configure_event_callback (GtkWidget *widget,
   GtkWidget *label = data;
   gchar *msg;
   gint x, y;
-
-  x = widget->allocation.x;
-  y = widget->allocation.y;
+  
+#if 0
+  /* FIXME */
+  gtk_window_get_location (GTK_WINDOW (widget), &x, &y);
+#else  
+  x = 0;
+  y = 0;
+#endif
   
   msg = g_strdup_printf ("event: %d,%d  %d x %d\n"
                          "location: %d, %d",
@@ -8235,6 +8266,26 @@ set_location_callback (GtkWidget *widget,
   gtk_widget_set_uposition (g_object_get_data (data, "target"), x, y);
 }
 
+static void
+set_geometry_callback (GtkWidget *entry,
+                       gpointer   data)
+{
+  gchar *text;
+  GtkWindow *target;
+
+  target = GTK_WINDOW (g_object_get_data (G_OBJECT (data), "target"));
+  
+  text = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, -1);
+
+#if 0
+  /* FIXME */
+  if (!gtk_window_parse_geometry (target, text))
+    g_print ("Bad geometry string '%s'\n", text);
+#endif
+  
+  g_free (text);
+}
+
 static void
 allow_shrink_callback (GtkWidget *widget,
                        gpointer   data)
@@ -8282,6 +8333,7 @@ window_controls (GtkWidget *window)
   GtkWidget *button;
   GtkWidget *spin;
   GtkAdjustment *adj;
+  GtkWidget *entry;
   GtkWidget *om;
   GtkWidget *menu;
   gint i;
@@ -8327,6 +8379,13 @@ window_controls (GtkWidget *window)
 
   g_object_set_data (G_OBJECT (control_window), "spin2", spin);
 
+  entry = gtk_entry_new ();
+  gtk_box_pack_start (GTK_BOX (vbox), entry, FALSE, FALSE, 0);
+
+  gtk_signal_connect (GTK_OBJECT (entry), "changed",
+                      GTK_SIGNAL_FUNC (set_geometry_callback),
+                      control_window);
+  
   button = gtk_button_new_with_label ("Queue resize");
   gtk_signal_connect_object (GTK_OBJECT (button),
                              "clicked",
@@ -8386,6 +8445,20 @@ window_controls (GtkWidget *window)
                       GTK_OBJECT (control_window));
   gtk_box_pack_end (GTK_BOX (vbox), button, FALSE, FALSE, 0);
 
+  button = gtk_button_new_with_mnemonic ("_Show");
+  gtk_signal_connect_object (GTK_OBJECT (button),
+                             "clicked",
+                             GTK_SIGNAL_FUNC (gtk_widget_show),
+                             GTK_OBJECT (window));
+  gtk_box_pack_end (GTK_BOX (vbox), button, FALSE, FALSE, 0);
+
+  button = gtk_button_new_with_mnemonic ("_Hide");
+  gtk_signal_connect_object (GTK_OBJECT (button),
+                             "clicked",
+                             GTK_SIGNAL_FUNC (gtk_widget_hide),
+                             GTK_OBJECT (window));
+  gtk_box_pack_end (GTK_BOX (vbox), button, FALSE, FALSE, 0);
+  
   menu = gtk_menu_new ();
   
   i = 0;
index a473837cda3b751d073202a8c2a49ce76accd18a..175e4f1c4b88c3291c3edc42b8450356551d142c 100644 (file)
@@ -1063,6 +1063,23 @@ do_apply_colors (gpointer callback_data,
     }
 }
 
+static void
+do_remove_tags (gpointer callback_data,
+                guint callback_action,
+                GtkWidget *widget)
+{
+  View *view = view_from_widget (widget);
+  GtkTextIter start;
+  GtkTextIter end;
+  
+  if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
+                                            &start, &end))
+    {
+      gtk_text_buffer_remove_all_tags (view->buffer->buffer,
+                                       &start, &end);
+    }
+}
+
 enum
 {
   RESPONSE_FORWARD,
@@ -1235,6 +1252,7 @@ static GtkItemFactoryEntry menu_items[] =
   { "/Attributes/Default tabs",          NULL,         do_apply_tabs, TRUE, NULL },
   { "/Attributes/Color cycles",          NULL,         do_apply_colors, TRUE, NULL },
   { "/Attributes/No colors",                     NULL,         do_apply_colors, FALSE, NULL },
+  { "/Attributes/Remove all tags",       NULL, do_remove_tags, 0, NULL },
   { "/_Test",           NULL,         0,           0, "<Branch>" },
   { "/Test/_Example",           NULL,         do_example,  0, NULL },
 };